Пример #1
0
def home():
    """Generates the home page view template.

    Returns:
        Template with context.
    """
    form = HiddenNameDescriptionForm()
    sketches = Sketch.all_with_acl().filter(
        not_(Sketch.Status.status == u'deleted'),
        Sketch.Status.parent).order_by(Sketch.updated_at.desc())
    # Only render upload button if it is configured.
    upload_enabled = current_app.config[u'UPLOAD_ENABLED']

    # Handle form for creating a new sketch.
    if form.validate_on_submit():
        sketch = Sketch(name=form.name.data,
                        description=form.description.data,
                        user=current_user)
        sketch.status.append(sketch.Status(user=None, status=u'new'))
        # Give the requesting user permissions on the new sketch.
        sketch.grant_permission(permission=u'read', user=current_user)
        sketch.grant_permission(permission=u'write', user=current_user)
        sketch.grant_permission(permission=u'delete', user=current_user)
        db_session.add(sketch)
        db_session.commit()
        return redirect(url_for(u'sketch_views.overview', sketch_id=sketch.id))

    return render_template(u'home/home.html',
                           sketches=sketches,
                           form=form,
                           upload_enabled=upload_enabled)
Пример #2
0
def _create_mock_event(event_id, quantity, time_diffs=None, source_attrs=None):
    """
    Returns an instance of Event, based on the MockDataStore event_dict
    example.

    Args:
        event_id: Desired ID for the Event.
        quantity: The number of Events to be generated.
        time_diffs: A list of time differences between the generated
        Events.
        source_attrs: Dictionary of attributes to add to the source of the
        generated events.
    Returns:
        A generator of Event objects.
    """

    if not time_diffs:
        time_diffs = [0]
    if quantity < 0:
        quantity = abs(quantity)

    # If the list of time differences is too small to be compatible
    # with the quantity of events, then extend the list with the last
    # value for as many items as necessary.
    if quantity - len(time_diffs) > 0:
        time_diffs.extend([time_diffs[len(time_diffs) - 1]] *
                          (quantity - len(time_diffs)))

    # Setup for Event object initialisation
    ds = MockDataStore('test', 0)
    user = User('test_user')
    sketch = Sketch('test_sketch', 'description', user)
    label = sketch.Label(label='Test label', user=user)
    sketch.labels.append(label)

    event_timestamp = 1410895419859714
    event_template = ds.get_event('test', 'test')

    for i in range(quantity):
        eventObj = _create_eventObj(ds, sketch, event_template, event_id,
                                    event_timestamp, source_attrs)
        yield eventObj

        # adding extra events after every requested event for better
        # simulation of real timeline data i.e. working with a larger
        # dataset
        for _ in range(100):
            event_timestamp += 1
            event_id += 1
            eventObj = _create_eventObj(ds, sketch, event_template, event_id,
                                        event_timestamp, source_attrs)
            yield eventObj

        event_timestamp += abs(time_diffs[i])
        event_id += 1
Пример #3
0
def home():
    """Generates the home page view template.

    Returns:
        Template with context.
    """
    form = HiddenNameDescriptionForm()
    sketches = Sketch.all_with_acl().filter(
        not_(Sketch.Status.status == 'deleted'),
        Sketch.Status.parent).order_by(Sketch.updated_at.desc())
    # Only render upload button if it is configured.
    upload_enabled = current_app.config['UPLOAD_ENABLED']

    # Handle form for creating a new sketch.
    if form.validate_on_submit():
        sketch = Sketch(
            name=form.name.data,
            description=form.description.data,
            user=current_user)
        sketch.status.append(sketch.Status(user=None, status='new'))
        db_session.add(sketch)
        db_session.commit()

        # Give the requesting user permissions on the new sketch.
        sketch.grant_permission(permission='read', user=current_user)
        sketch.grant_permission(permission='write', user=current_user)
        sketch.grant_permission(permission='delete', user=current_user)
        return redirect(url_for('sketch_views.overview', sketch_id=sketch.id))

    return render_template(
        'home/home.html',
        sketches=sketches,
        form=form,
        upload_enabled=upload_enabled)
Пример #4
0
def home():
    """Generates the home page view template.

    Returns:
        Template with context.
    """
    form = HiddenNameDescriptionForm()
    sketches = Sketch.all_with_acl().filter(
        not_(Sketch.Status.status == u'deleted'),
        Sketch.Status.parent).order_by(Sketch.updated_at.desc())
    query_filter = request.args.get(u'filter', u'')
    query = request.args.get(u'q', u'')
    # Only render upload button if it is configured.
    upload_enabled = current_app.config[u'UPLOAD_ENABLED']
    last_sketch = View.query.filter_by(user=current_user, name=u'').order_by(
        View.updated_at.desc()).first()

    if query_filter:
        if query_filter == u'user':
            sketches = sketches.filter(Sketch.user == current_user)
        elif query_filter == u'shared':
            sketches = sketches.filter(not_(Sketch.user == current_user))

    # TODO: Figure out a better way to handle this.
    if query:
        if query.startswith(u'*'):
            query = u''
        else:
            sketches = sketches.filter(Sketch.name.contains(query)).limit(100)

    # Handle form for creating a new sketch.
    if form.validate_on_submit():
        sketch = Sketch(name=form.name.data,
                        description=form.description.data,
                        user=current_user)
        sketch.status.append(sketch.Status(user=None, status=u'new'))
        # Give the requesting user permissions on the new sketch.
        sketch.grant_permission(permission=u'read', user=current_user)
        sketch.grant_permission(permission=u'write', user=current_user)
        sketch.grant_permission(permission=u'delete', user=current_user)
        db_session.add(sketch)
        db_session.commit()
        return redirect(url_for(u'sketch_views.overview', sketch_id=sketch.id))

    return render_template(u'home/home.html',
                           sketches=sketches,
                           form=form,
                           query=query,
                           upload_enabled=upload_enabled,
                           last_sketch=last_sketch)
Пример #5
0
    def get(self):
        """Handles GET request to the resource.

        Returns:
            List of sketches (instance of flask.wrappers.Response)
        """
        if current_user.admin:
            sketch_query = Sketch.query
        else:
            sketch_query = Sketch.all_with_acl()

        filtered_sketches = sketch_query.filter(
            not_(Sketch.Status.status == 'deleted'),
            Sketch.Status.parent).order_by(Sketch.updated_at.desc()).all()

        # Just return a subset of the sketch objects to reduce the amount of
        # data returned.
        sketches = []
        for sketch in filtered_sketches:
            sketches.append({
                'name': sketch.name,
                'updated_at': str(sketch.updated_at),
                'user': sketch.user.username,
                'id': sketch.id,
                'status': sketch.get_status.status
            })
        meta = {'current_user': current_user.username}
        return jsonify({'objects': sketches, 'meta': meta})
Пример #6
0
    def _create_sketch(self, name, user, acl=False):
        """Create a sketch in the database.

        Args:
            name: Name of the sketch (string)
            user: A user (instance of timesketch.models.user.User)
            acl: Boolean value to decide if ACL permissions should be set

        Returns:
            A sketch (instance of timesketch.models.sketch.Sketch)
        """
        sketch = Sketch(name=name, description=name, user=user)
        if acl:
            for permission in [u'read', u'write', u'delete']:
                sketch.grant_permission(user=user, permission=permission)
        label = sketch.Label(label=u'Test label', user=user)
        status = sketch.Status(status=u'Test status', user=user)
        sketch.labels.append(label)
        sketch.status.append(status)
        self._commit_to_database(sketch)
        return sketch
Пример #7
0
    def test_get_event_data(self):
        """Test getEventData returns the correct values."""
        user = User("test_user")
        sketch = Sketch("test_sketch", "description", user)
        label = sketch.Label(label="Test label", user=user)
        sketch.labels.append(label)

        index = "test_index"
        sketch_id = 1

        for analyzer_class in self.analyzer_classes:
            analyzer = analyzer_class["class"](index, sketch_id)
            datastore = analyzer.datastore
            event_dict = copy.deepcopy(MockDataStore.event_dict)
            event_dict["_source"].update({"xml_string": xml_string1})
            event_obj = Event(event_dict, datastore, sketch)

            username = analyzer.getEventData(event_obj, "TargetUserName")
            logon_id = analyzer.getEventData(event_obj, "TargetLogonId")

            self.assertEqual(username, "USER_1")
            self.assertEqual(logon_id, "0x0000000000000001")
Пример #8
0
    def test_get_event_data(self):
        """Test getEventData returns the correct values."""
        user = User('test_user')
        sketch = Sketch('test_sketch', 'description', user)
        label = sketch.Label(label='Test label', user=user)
        sketch.labels.append(label)

        index = 'test_index'
        sketch_id = 1

        for analyzer_class in self.analyzer_classes:
            analyzer = analyzer_class['class'](index, sketch_id)
            datastore = analyzer.datastore
            event_dict = copy.deepcopy(MockDataStore.event_dict)
            event_dict['_source'].update({'xml_string': xml_string1})
            event_obj = Event(event_dict, datastore, sketch)

            username = analyzer.getEventData(event_obj, 'TargetUserName')
            logon_id = analyzer.getEventData(event_obj, 'TargetLogonId')

            self.assertEqual(username, 'USER_1')
            self.assertEqual(logon_id, '0x0000000000000001')
Пример #9
0
def home():
    """Generates the home page view template.

    Returns:
        Template with context.
    """
    form = HiddenNameDescriptionForm()
    sketches = Sketch.all_with_acl().filter(
        not_(Sketch.Status.status == u'deleted'),
        Sketch.Status.parent).order_by(Sketch.updated_at.desc())
    query_filter = request.args.get(u'filter', u'')
    query = request.args.get(u'q', u'')
    # Only render upload button if it is configured.
    upload_enabled = current_app.config[u'UPLOAD_ENABLED']
    last_sketch = View.query.filter_by(
        user=current_user, name=u'').order_by(
            View.updated_at.desc()).first()

    if query_filter:
        if query_filter == u'user':
            sketches = sketches.filter(Sketch.user == current_user)
        elif query_filter == u'shared':
            sketches = sketches.filter(not_(Sketch.user == current_user))

    # TODO: Figure out a better way to handle this.
    if query:
        if query.startswith(u'*'):
            query = u''
        else:
            sketches = sketches.filter(Sketch.name.contains(query)).limit(100)

    # Handle form for creating a new sketch.
    if form.validate_on_submit():
        sketch = Sketch(
            name=form.name.data, description=form.description.data,
            user=current_user)
        sketch.status.append(sketch.Status(user=None, status=u'new'))
        # Give the requesting user permissions on the new sketch.
        sketch.grant_permission(current_user, u'read')
        sketch.grant_permission(current_user, u'write')
        sketch.grant_permission(current_user, u'delete')
        db_session.add(sketch)
        db_session.commit()
        return redirect(url_for(u'sketch_views.overview', sketch_id=sketch.id))

    return render_template(
        u'home/home.html', sketches=sketches, form=form, query=query,
        upload_enabled=upload_enabled, last_sketch=last_sketch)
Пример #10
0
    def post(self):
        """Handles POST request to the resource.

        Returns:
            A sketch in JSON (instance of flask.wrappers.Response)
        """
        form = NameDescriptionForm.build(request)
        if form.validate_on_submit():
            sketch = Sketch(name=form.name.data,
                            description=form.description.data,
                            user=current_user)
            sketch.status.append(sketch.Status(user=None, status=u'new'))
            # Give the requesting user permissions on the new sketch.
            sketch.grant_permission(permission=u'read', user=current_user)
            sketch.grant_permission(permission=u'write', user=current_user)
            sketch.grant_permission(permission=u'delete', user=current_user)
            db_session.add(sketch)
            db_session.commit()
            return self.to_json(sketch, status_code=HTTP_STATUS_CODE_CREATED)
        return abort(HTTP_STATUS_CODE_BAD_REQUEST)
Пример #11
0
 def _create_sketch(self, name, user, acl=False):
     """Create a sketch in the database.
     Args:
         name: Name of the sketch (string)
         user: A user (instance of timesketch.models.user.User)
         acl: Boolean value to decide if ACL permissions should be set
     Returns:
         A sketch (instance of timesketch.models.sketch.Sketch)
     """
     sketch = Sketch.get_or_create(name=name, description=name, user=user)
     if acl:
         for permission in ['read', 'write', 'delete']:
             sketch.grant_permission(permission=permission, user=user)
     label = sketch.Label(label='Test label', user=user)
     status = sketch.Status(status='Test status', user=user)
     sketch.labels.append(label)
     sketch.status.append(status)
     self._commit_to_database(sketch)
     return sketch
Пример #12
0
    def get(self):
        """Handles GET request to the resource.

        Returns:
            List of sketches (instance of flask.wrappers.Response)
        """
        # TODO: Handle offset parameter
        sketches = Sketch.all_with_acl()
        paginated_result = sketches.paginate(1, 10, False)
        meta = {
            u'next': paginated_result.next_num,
            u'previous': paginated_result.prev_num,
            u'offset': paginated_result.page,
            u'limit': paginated_result.per_page
        }
        if not paginated_result.has_prev:
            meta[u'previous'] = None
        if not paginated_result.has_next:
            meta[u'next'] = None
        result = self.to_json(paginated_result.items, meta=meta)
        return result
Пример #13
0
    def get(self):
        """Handles GET request to the resource.

        Returns:
            List of sketches (instance of flask.wrappers.Response)
        """
        # TODO: Handle offset parameter
        sketches = Sketch.all_with_acl()
        paginated_result = sketches.paginate(1, 10, False)
        meta = {
            u'next': paginated_result.next_num,
            u'previous': paginated_result.prev_num,
            u'offset': paginated_result.page,
            u'limit': paginated_result.per_page
        }
        if not paginated_result.has_prev:
            meta[u'previous'] = None
        if not paginated_result.has_next:
            meta[u'next'] = None
        result = self.to_json(paginated_result.items, meta=meta)
        return result
Пример #14
0
    def post(self):
        """Handles POST request to the resource.

        Returns:
            A sketch in JSON (instance of flask.wrappers.Response)
        """
        form = NameDescriptionForm.build(request)
        if form.validate_on_submit():
            sketch = Sketch(
                name=form.name.data, description=form.description.data,
                user=current_user)
            sketch.status.append(sketch.Status(user=None, status=u'new'))
            # Give the requesting user permissions on the new sketch.
            sketch.grant_permission(permission=u'read', user=current_user)
            sketch.grant_permission(permission=u'write', user=current_user)
            sketch.grant_permission(permission=u'delete', user=current_user)
            db_session.add(sketch)
            db_session.commit()
            return self.to_json(sketch, status_code=HTTP_STATUS_CODE_CREATED)
        return abort(HTTP_STATUS_CODE_BAD_REQUEST)
Пример #15
0
    def get(self):
        """Handles GET request to the resource.

        Returns:
            List of sketches (instance of flask.wrappers.Response)
        """
        args = self.parser.parse_args()
        scope = args.get("scope")
        page = args.get("page")
        per_page = args.get("per_page")
        search_query = args.get("search_query")
        include_archived = args.get("include_archived")

        if current_user.admin and scope == "admin":
            sketch_query = Sketch.query
        else:
            sketch_query = Sketch.all_with_acl()

        base_filter = sketch_query.filter(
            not_(Sketch.Status.status == "deleted"),
            not_(Sketch.Status.status == "archived"),
            Sketch.Status.parent,
        ).order_by(Sketch.updated_at.desc())

        base_filter_with_archived = sketch_query.filter(
            not_(Sketch.Status.status == "deleted"),
            Sketch.Status.parent).order_by(Sketch.updated_at.desc())

        filtered_sketches = base_filter_with_archived
        sketches = []
        return_sketches = []

        has_next = False
        has_prev = False
        next_page = None
        prev_page = None
        current_page = 1
        total_pages = 0
        total_items = 0

        if scope == "recent":
            # Get list of sketches that the user has actively searched in.
            # TODO: Make this cover more actions such as story updates etc.
            # TODO: Right now we only return the top 3, make this configurable.
            views = (View.query.filter_by(user=current_user, name="").order_by(
                View.updated_at.desc()).limit(3))
            sketches = [view.sketch for view in views]
            total_items = len(sketches)
        elif scope == "admin":
            if not current_user.admin:
                abort(HTTP_STATUS_CODE_FORBIDDEN, "User is not an admin.")
            if include_archived:
                filtered_sketches = base_filter_with_archived
            else:
                filtered_sketches = base_filter
        elif scope == "user":
            filtered_sketches = base_filter.filter_by(user=current_user)
        elif scope == "archived":
            filtered_sketches = sketch_query.filter(
                Sketch.status.any(status="archived"))
        elif scope == "shared":
            filtered_sketches = base_filter.filter(Sketch.user != current_user)
        elif scope == "search":
            filtered_sketches = base_filter_with_archived.filter(
                or_(
                    Sketch.name.ilike(f"%{search_query}%"),
                    Sketch.description.ilike(f"%{search_query}%"),
                ))

        if not sketches:
            pagination = filtered_sketches.paginate(page=page,
                                                    per_page=per_page)
            sketches = pagination.items
            has_next = pagination.has_next
            has_prev = pagination.has_prev
            next_page = pagination.next_num
            prev_page = pagination.prev_num
            current_page = pagination.page
            total_pages = pagination.pages
            total_items = pagination.total

        for sketch in sketches:
            # Return a subset of the sketch objects to reduce the amount of
            # data sent to the client.
            return_sketches.append({
                "id":
                sketch.id,
                "name":
                sketch.name,
                "description":
                sketch.description,
                "created_at":
                str(sketch.created_at),
                "last_activity":
                utils.get_sketch_last_activity(sketch),
                "user":
                sketch.user.username,
                "status":
                sketch.get_status.status,
            })

        meta = {
            "current_user": current_user.username,
            "has_next": has_next,
            "has_prev": has_prev,
            "next_page": next_page,
            "prev_page": prev_page,
            "current_page": current_page,
            "total_pages": total_pages,
            "total_items": total_items,
        }
        return jsonify({"objects": return_sketches, "meta": meta})
Пример #16
0
    def run(self, file_path, sketch_id, username, timeline_name):
        """This is the run method."""

        file_path = os.path.realpath(file_path)
        file_path_no_extension, extension = os.path.splitext(file_path)
        extension = extension.lstrip('.')
        filename = os.path.basename(file_path_no_extension)

        supported_extensions = ('plaso', 'csv', 'jsonl')

        if not os.path.isfile(file_path):
            sys.exit('No such file: {0:s}'.format(file_path))

        if extension not in supported_extensions:
            sys.exit('Extension {0:s} is not supported. '
                     '(supported extensions are: {1:s})'.format(
                         extension, ', '.join(supported_extensions)))

        user = None
        if not username:
            username = pwd.getpwuid(os.stat(file_path).st_uid).pw_name
        if not username == 'root':
            if not isinstance(username, six.text_type):
                username = codecs.decode(username, 'utf-8')
            user = User.query.filter_by(username=username).first()
        if not user:
            sys.exit('Cannot determine user for file: {0:s}'.format(file_path))

        sketch = None
        # If filename starts with <number> then use that as sketch_id.
        # E.g: 42_file_name.plaso means sketch_id is 42.
        sketch_id_from_filename = filename.split('_')[0]
        if not sketch_id and sketch_id_from_filename.isdigit():
            sketch_id = sketch_id_from_filename

        if sketch_id:
            try:
                sketch = Sketch.query.get_with_acl(sketch_id, user=user)
            except Forbidden:
                pass

        if not timeline_name:
            if timeline_name is None:
                timeline_name = '{0:s}_timeline'.format(filename)

            if not isinstance(timeline_name, six.text_type):
                timeline_name = codecs.decode(timeline_name, 'utf-8')

            timeline_name = timeline_name.replace('_', ' ')
            # Remove sketch ID if present in the filename.
            timeline_parts = timeline_name.split()
            if timeline_parts[0].isdigit():
                timeline_name = ' '.join(timeline_name.split()[1:])

        if not sketch:
            # Create a new sketch.
            sketch_name = 'Sketch for: {0:s}'.format(timeline_name)
            sketch = Sketch(name=sketch_name,
                            description=sketch_name,
                            user=user)
            # Need to commit here to be able to set permissions later.
            db_session.add(sketch)
            db_session.commit()
            sketch.grant_permission(permission='read', user=user)
            sketch.grant_permission(permission='write', user=user)
            sketch.grant_permission(permission='delete', user=user)
            sketch.status.append(sketch.Status(user=None, status='new'))
            db_session.add(sketch)
            db_session.commit()

        index_name = uuid.uuid4().hex
        if not isinstance(index_name, six.text_type):
            index_name = codecs.decode(index_name, 'utf-8')

        searchindex = SearchIndex.get_or_create(name=timeline_name,
                                                description=timeline_name,
                                                user=user,
                                                index_name=index_name)

        searchindex.grant_permission(permission='read', user=user)
        searchindex.grant_permission(permission='write', user=user)
        searchindex.grant_permission(permission='delete', user=user)

        searchindex.set_status('processing')
        db_session.add(searchindex)
        db_session.commit()

        if sketch and sketch.has_permission(user, 'write'):
            timeline = Timeline(name=searchindex.name,
                                description=searchindex.description,
                                sketch=sketch,
                                user=user,
                                searchindex=searchindex)
            timeline.set_status('processing')
            sketch.timelines.append(timeline)
            db_session.add(timeline)
            db_session.commit()

        # Start Celery pipeline for indexing and analysis.
        # Import here to avoid circular imports.
        from timesketch.lib import tasks  # pylint: disable=import-outside-toplevel
        pipeline = tasks.build_index_pipeline(file_path=file_path,
                                              events='',
                                              timeline_name=timeline_name,
                                              index_name=index_name,
                                              file_extension=extension,
                                              sketch_id=sketch.id)
        pipeline.apply_async(task_id=index_name)

        print('Imported {0:s} to sketch: {1:d} ({2:s})'.format(
            file_path, sketch.id, sketch.name))
Пример #17
0
def setup_sketch(timeline_name, index_name, username, sketch_id=None):
    """Use existing sketch or create a new sketch.

    Args:
        timeline_name: (str) Name of the Timeline
        index_name: (str) Name of the index
        username: (str) Who should own the timeline
        sketch_id: (str) Optional sketch_id to add timeline to

    Returns:
        (tuple) sketch ID and timeline ID as integers
    """
    with app.app_context():
        user = User.get_or_create(username=username)
        sketch = None

        if sketch_id:
            try:
                sketch = Sketch.query.get_with_acl(sketch_id, user=user)
                logger.info('Using existing sketch: {} ({})'.format(
                    sketch.name, sketch.id))
            except Forbidden:
                pass

        if not (sketch or sketch_id):
            # Create a new sketch.
            sketch_name = 'Turbinia: {}'.format(timeline_name)
            sketch = Sketch(name=sketch_name,
                            description=sketch_name,
                            user=user)
            # Need to commit here to be able to set permissions later.
            db_session.add(sketch)
            db_session.commit()
            sketch.grant_permission(permission='read', user=user)
            sketch.grant_permission(permission='write', user=user)
            sketch.grant_permission(permission='delete', user=user)
            sketch.status.append(sketch.Status(user=None, status='new'))
            db_session.add(sketch)
            db_session.commit()
            logger.info('Created new sketch: {} ({})'.format(
                sketch.name, sketch.id))

        searchindex = SearchIndex.get_or_create(
            name=timeline_name,
            description='Created by Turbinia.',
            user=user,
            index_name=index_name)
        searchindex.grant_permission(permission='read', user=user)
        searchindex.grant_permission(permission='write', user=user)
        searchindex.grant_permission(permission='delete', user=user)
        searchindex.set_status('processing')
        db_session.add(searchindex)
        db_session.commit()

        timeline = Timeline(name=searchindex.name,
                            description=searchindex.description,
                            sketch=sketch,
                            user=user,
                            searchindex=searchindex)

        # If the user doesn't have write access to the sketch then create the
        # timeline but don't attach it to the sketch.
        if not sketch.has_permission(user, 'write'):
            timeline.sketch = None
        else:
            sketch.timelines.append(timeline)

        db_session.add(timeline)
        db_session.commit()
        timeline.set_status('processing')

        return sketch.id, timeline.id
Пример #18
0
    def get(self):
        """Handles GET request to the resource.

        Returns:
            List of sketches (instance of flask.wrappers.Response)
        """
        args = self.parser.parse_args()
        scope = args.get('scope')
        page = args.get('page')
        per_page = args.get('per_page')
        search_query = args.get('search_query')
        include_archived = args.get('include_archived')

        if current_user.admin and scope == 'admin':
            sketch_query = Sketch.query
        else:
            sketch_query = Sketch.all_with_acl()

        base_filter = sketch_query.filter(
            not_(Sketch.Status.status == 'deleted'),
            not_(Sketch.Status.status == 'archived'),
            Sketch.Status.parent).order_by(Sketch.updated_at.desc())

        base_filter_with_archived = sketch_query.filter(
            not_(Sketch.Status.status == 'deleted'),
            Sketch.Status.parent).order_by(Sketch.updated_at.desc())

        filtered_sketches = base_filter_with_archived
        sketches = []
        return_sketches = []

        has_next = False
        has_prev = False
        next_page = None
        prev_page = None
        current_page = 1
        total_pages = 0
        total_items = 0

        if scope == 'recent':
            # Get list of sketches that the user has actively searched in.
            # TODO: Make this cover more actions such as story updates etc.
            # TODO: Right now we only return the top 3, make this configurable.
            views = View.query.filter_by(
                user=current_user, name='').order_by(
                View.updated_at.desc()).limit(3)
            sketches = [view.sketch for view in views]
            total_items = len(sketches)
        elif scope == 'admin':
            if not current_user.admin:
                abort(HTTP_STATUS_CODE_FORBIDDEN, 'User is not an admin.')
            if include_archived:
                filtered_sketches = base_filter_with_archived
            else:
                filtered_sketches = base_filter
        elif scope == 'user':
            filtered_sketches = base_filter.filter_by(user=current_user)
        elif scope == 'archived':
            filtered_sketches = sketch_query.filter(
                Sketch.status.any(status='archived'))
        elif scope == 'shared':
            filtered_sketches = base_filter.filter(Sketch.user != current_user)
        elif scope == 'search':
            filtered_sketches = base_filter_with_archived.filter(
                or_(
                    Sketch.name.ilike(f'%{search_query}%'),
                    Sketch.description.ilike(f'%{search_query}%')
                )
            )

        if not sketches:
            pagination = filtered_sketches.paginate(
                page=page, per_page=per_page)
            sketches = pagination.items
            has_next = pagination.has_next
            has_prev = pagination.has_prev
            next_page = pagination.next_num
            prev_page = pagination.prev_num
            current_page = pagination.page
            total_pages = pagination.pages
            total_items = pagination.total

        for sketch in sketches:
            # Return a subset of the sketch objects to reduce the amount of
            # data sent to the client.
            return_sketches.append({
                'id': sketch.id,
                'name': sketch.name,
                'description': sketch.description,
                'created_at': str(sketch.created_at),
                'last_activity': utils.get_sketch_last_activity(sketch),
                'user': sketch.user.username,
                'status': sketch.get_status.status
            })

        meta = {
            'current_user': current_user.username,
            'has_next': has_next,
            'has_prev': has_prev,
            'next_page': next_page,
            'prev_page': prev_page,
            'current_page': current_page,
            'total_pages': total_pages,
            'total_items': total_items
        }
        return jsonify({'objects': return_sketches, 'meta': meta})
Пример #19
0
    def run(self, file_path, sketch_id, username, timeline_name):
        """This is the run method."""

        file_path = os.path.realpath(file_path)
        file_path_no_extension, extension = os.path.splitext(file_path)
        extension = extension.lstrip('.')
        filename = os.path.basename(file_path_no_extension)

        supported_extensions = ('plaso', 'csv', 'jsonl')

        if not os.path.isfile(file_path):
            sys.exit('No such file: {0:s}'.format(file_path))

        if extension not in supported_extensions:
            sys.exit(
                'Extension {0:s} is not supported. '
                '(supported extensions are: {1:s})'.format(
                    extension, ', '.join(supported_extensions)))

        user = None
        if not username:
            username = pwd.getpwuid(os.stat(file_path).st_uid).pw_name
        if not username == 'root':
            if not isinstance(username, six.text_type):
                username = codecs.decode(username, 'utf-8')
            user = User.query.filter_by(username=username).first()
        if not user:
            sys.exit('Cannot determine user for file: {0:s}'.format(file_path))

        sketch = None
        # If filename starts with <number> then use that as sketch_id.
        # E.g: 42_file_name.plaso means sketch_id is 42.
        sketch_id_from_filename = filename.split('_')[0]
        if not sketch_id and sketch_id_from_filename.isdigit():
            sketch_id = sketch_id_from_filename

        if sketch_id:
            try:
                sketch = Sketch.query.get_with_acl(sketch_id, user=user)
            except Forbidden:
                pass

        if not timeline_name:
            if not isinstance(timeline_name, six.text_type):
                timeline_name = codecs.decode(timeline_name, 'utf-8')

            timeline_name = timeline_name.replace('_', ' ')
            # Remove sketch ID if present in the filename.
            timeline_parts = timeline_name.split()
            if timeline_parts[0].isdigit():
                timeline_name = ' '.join(timeline_name.split()[1:])

        if not sketch:
            # Create a new sketch.
            sketch_name = 'Sketch for: {0:s}'.format(timeline_name)
            sketch = Sketch(
                name=sketch_name, description=sketch_name, user=user)
            # Need to commit here to be able to set permissions later.
            db_session.add(sketch)
            db_session.commit()
            sketch.grant_permission(permission='read', user=user)
            sketch.grant_permission(permission='write', user=user)
            sketch.grant_permission(permission='delete', user=user)
            sketch.status.append(sketch.Status(user=None, status='new'))
            db_session.add(sketch)
            db_session.commit()

        index_name = uuid.uuid4().hex
        if not isinstance(index_name, six.text_type):
            index_name = codecs.decode(index_name, 'utf-8')

        searchindex = SearchIndex.get_or_create(
            name=timeline_name,
            description=timeline_name,
            user=user,
            index_name=index_name)

        searchindex.grant_permission(permission='read', user=user)
        searchindex.grant_permission(permission='write', user=user)
        searchindex.grant_permission(permission='delete', user=user)

        searchindex.set_status('processing')
        db_session.add(searchindex)
        db_session.commit()

        if sketch and sketch.has_permission(user, 'write'):
            timeline = Timeline(
                name=searchindex.name,
                description=searchindex.description,
                sketch=sketch,
                user=user,
                searchindex=searchindex)
            timeline.set_status('processing')
            sketch.timelines.append(timeline)
            db_session.add(timeline)
            db_session.commit()

        # Start Celery pipeline for indexing and analysis.
        # Import here to avoid circular imports.
        from timesketch.lib import tasks
        pipeline = tasks.build_index_pipeline(
            file_path, timeline_name, index_name, extension, sketch.id)
        pipeline.apply_async(task_id=index_name)

        print('Imported {0:s} to sketch: {1:d} ({2:s})'.format(
            file_path, sketch.id, sketch.name))
Пример #20
0
    def get(self):
        """Handles GET request to the resource.

        Returns:
            List of sketches (instance of flask.wrappers.Response)
        """
        args = self.parser.parse_args()
        scope = args.get('scope', None)
        page = args.get('page', 1)
        search_query = args.get('search_query', None)

        if current_user.admin:
            sketch_query = Sketch.query
        else:
            sketch_query = Sketch.all_with_acl()

        base_filter = sketch_query.filter(
            not_(Sketch.Status.status == 'deleted'),
            not_(Sketch.Status.status == 'archived'),
            Sketch.Status.parent).order_by(Sketch.updated_at.desc())

        base_filter_with_archived = sketch_query.filter(
            not_(Sketch.Status.status == 'deleted'),
            Sketch.Status.parent).order_by(Sketch.updated_at.desc())

        filtered_sketches = base_filter_with_archived
        sketches = []
        return_sketches = []
        num_hits = 0

        if scope == 'recent':
            # Get list of sketches that the user has actively searched in.
            # TODO: Make this cover more actions such as story updates etc.
            # TODO: Right now we only return the top 3, make this configurable.
            views = View.query.filter_by(user=current_user, name='').order_by(
                View.updated_at.desc()).limit(3)
            sketches = [view.sketch for view in views]
            num_hits = len(sketches)
        elif scope == 'user':
            filtered_sketches = base_filter.filter_by(user=current_user)
        elif scope == 'archived':
            filtered_sketches = sketch_query.filter(
                Sketch.status.any(status='archived'))
        elif scope == 'shared':
            filtered_sketches = base_filter.filter(Sketch.user != current_user)
        elif scope == 'search':
            filtered_sketches = base_filter_with_archived.filter(
                or_(Sketch.name.ilike(f'%{search_query}%'),
                    Sketch.description.ilike(f'%{search_query}%')))

        # If no scope is set, fall back to returning all sketches.
        if not scope:
            sketches = filtered_sketches.all()

        if not sketches:
            pagination = filtered_sketches.paginate(page=page, per_page=20)
            sketches = pagination.items
            num_hits = pagination.total

        for sketch in sketches:
            # Last time a user did a query in the sketch, indicating activity.
            try:
                last_activity = View.query.filter_by(
                    sketch=sketch, name='').order_by(
                        View.updated_at.desc()).first().updated_at
            except AttributeError:
                last_activity = ''

            # Return a subset of the sketch objects to reduce the amount of
            # data sent to the client.
            return_sketches.append({
                'id': sketch.id,
                'name': sketch.name,
                'description': sketch.description,
                'created_at': str(sketch.created_at),
                'last_activity': str(last_activity),
                'user': sketch.user.username,
                'status': sketch.get_status.status
            })

        meta = {'current_user': current_user.username, 'num_hits': num_hits}
        return jsonify({'objects': return_sketches, 'meta': meta})