Exemplo n.º 1
0
def show_cve(cve, path=None):
    data = get_cve_data(cve)
    if not data:
        return not_found()

    packages = list(
        set(
            sorted([
                item for sublist in data['group_packages'].values()
                for item in sublist
            ])))
    title = '{} - {}'.format(data['issue'].id, ' '.join(packages)) \
            if len(packages) else \
            '{}'.format(data['issue'].id)

    advisories = data['advisories']
    if not current_user.role.is_reporter:
        advisories = list(
            filter(
                lambda advisory: advisory.publication == Publication.published,
                advisories))

    return render_template('cve.html',
                           title=title,
                           issue=data['issue'],
                           groups=data['groups'],
                           group_packages=data['group_packages'],
                           advisories=advisories,
                           can_edit=user_can_edit_issue(advisories),
                           can_delete=user_can_delete_issue(advisories))
Exemplo n.º 2
0
def todo():
    entries = get_todo_data()
    return render_template('todo.html',
                           title='Todo Lists',
                           entries=entries,
                           smiley=smileys_happy[randint(
                               0,
                               len(smileys_happy) - 1)],
                           can_handle_advisory=user_can_handle_advisory(),
                           can_edit_group=user_can_edit_group(),
                           can_edit_issue=user_can_edit_issue())
Exemplo n.º 3
0
def add_cve():
    form = CVEForm()
    if not form.validate_on_submit():
        return render_template('form/cve.html',
                               title='Add CVE',
                               form=form,
                               CVE=CVE)

    cve = db.get(CVE, id=form.cve.data)
    if cve is not None:
        advisories = (db.session.query(Advisory).join(
            CVEGroupEntry, CVEGroupEntry.cve_id == cve.id).join(
                CVEGroup, CVEGroupEntry.group).join(
                    CVEGroupPackage, CVEGroup.packages).filter(
                        Advisory.group_package_id == CVEGroupPackage.id)
                      ).all()
        if not user_can_edit_issue(advisories):
            flash(ERROR_ISSUE_REFERENCED_BY_ADVISORY.format(cve.id), 'error')
            return forbidden()

        not_merged = []
        merged = False

        # try to merge issue_type
        if 'unknown' != form.issue_type.data:
            if 'unknown' == cve.issue_type:
                cve.issue_type = form.issue_type.data
                merged = True
            elif form.issue_type.data != cve.issue_type:
                not_merged.append(form.issue_type)
        form.issue_type.data = cve.issue_type

        # try to merge severity
        form_severity = Severity.fromstring(form.severity.data)
        if Severity.unknown != form_severity:
            if Severity.unknown == cve.severity:
                cve.severity = form_severity
                merged = True
            elif form_severity != cve.severity:
                not_merged.append(form.severity)
        form.severity.data = cve.severity.name

        # try to merge remote
        form_remote = Remote.fromstring(form.remote.data)
        if Remote.unknown != form_remote:
            if Remote.unknown == cve.remote:
                cve.remote = form_remote
                merged = True
            elif form_remote != cve.remote:
                not_merged.append(form.remote)
        form.remote.data = cve.remote.name

        # try to merge description
        if form.description.data:
            if not cve.description:
                cve.description = form.description.data
                merged = True
            elif form.description.data != cve.description:
                not_merged.append(form.description)
        form.description.data = cve.description

        # try to merge references
        references = cve.reference.splitlines() if cve.reference else []
        old_references = references.copy()
        form_references = form.reference.data.splitlines(
        ) if form.reference.data else []
        for reference in form_references:
            if reference not in references:
                references.append(reference)
                merged = True
        if old_references != references:
            cve.reference = '\n'.join(references)
        form.reference.data = cve.reference

        # try to merge notes
        if form.notes.data:
            if not cve.notes:
                cve.notes = form.notes.data
                merged = True
            elif form.notes.data != cve.notes:
                not_merged.append(form.notes)
        form.notes.data = cve.notes

        # if something got merged, commit and flash
        if merged:
            db.session.commit()
            flash(CVE_MERGED.format(cve.id))

        # warn if something failed to be merged
        if not_merged:
            for field in not_merged:
                field.errors.append(ERROR_UNMERGEABLE)

            not_merged_labels = [field.label.text for field in not_merged]
            flash(
                CVE_MERGED_PARTIALLY.format(cve.id,
                                            ', '.join(not_merged_labels)),
                'warning')
            return render_template('form/cve.html',
                                   title='Edit {}'.format(cve),
                                   form=form,
                                   CVE=CVE,
                                   action='{}/edit'.format(cve.id))

        return redirect('/{}'.format(cve.id))

    cve = CVE()
    cve.id = form.cve.data
    cve.issue_type = form.issue_type.data
    cve.description = form.description.data
    cve.severity = Severity.fromstring(form.severity.data)
    cve.remote = Remote.fromstring(form.remote.data)
    cve.reference = form.reference.data
    cve.notes = form.notes.data
    db.session.add(cve)
    db.session.commit()
    flash('Added {}'.format(cve.id))
    return redirect('/{}'.format(cve.id))
Exemplo n.º 4
0
def edit_cve(cve):
    entries = (db.session.query(CVE, CVEGroup, Advisory)
               .filter(CVE.id == cve)
               .outerjoin(CVEGroupEntry, CVEGroupEntry.cve_id == CVE.id)
               .outerjoin(CVEGroup, CVEGroupEntry.group)
               .outerjoin(CVEGroupPackage, CVEGroup.packages)
               .outerjoin(Advisory, Advisory.group_package_id == CVEGroupPackage.id)).all()
    if not entries:
        return not_found()

    cve = entries[0][0]
    groups = set(group for (cve, group, advisory) in entries if group)
    advisories = set(advisory for (cve, group, advisory) in entries if advisory)

    if not user_can_edit_issue(advisories):
        return forbidden()

    form = CVEForm(edit=True)
    if not form.is_submitted():
        form.cve.data = cve.id
        form.issue_type.data = cve.issue_type
        form.description.data = cve.description
        form.severity.data = cve.severity.name
        form.remote.data = cve.remote.name
        form.reference.data = cve.reference
        form.notes.data = cve.notes
    if not form.validate_on_submit():
        if advisories:
            flash('WARNING: This is referenced by an already published advisory!', 'warning')
        return render_template('form/cve.html',
                               title='Edit {}'.format(cve),
                               form=form,
                               CVE=CVE)

    severity = Severity.fromstring(form.severity.data)
    severity_changed = cve.severity != severity
    issue_type_changed = cve.issue_type != form.issue_type.data

    cve.issue_type = form.issue_type.data
    cve.description = form.description.data
    cve.severity = severity
    cve.remote = Remote.fromstring(form.remote.data)
    cve.reference = form.reference.data
    cve.notes = form.notes.data

    if severity_changed or issue_type_changed:
        # update cached group severity for all goups containing this issue
        group_ids = [group.id for group in groups]
        issues = (db.session.query(CVEGroup, CVE)
                  .join(CVEGroupEntry, CVEGroup.issues)
                  .join(CVE, CVEGroupEntry.cve)
                  .group_by(CVEGroup.id).group_by(CVE.id))
        if group_ids:
            issues = issues.filter(CVEGroup.id.in_(group_ids))
        issues = (issues).all()

        if severity_changed:
            group_severity = defaultdict(list)
            for group, issue in issues:
                group_severity[group].append(issue.severity)
            for group, severities in group_severity.items():
                group.severity = highest_severity(severities)

        # update scheduled advisories if the issue type changes
        if advisories and issue_type_changed:
            group_issue_type = defaultdict(set)
            for group, issue in issues:
                group_issue_type[group].add(issue.issue_type)
            for advisory in advisories:
                if Publication.published == advisory.publication:
                    continue
                issue_types = group_issue_type[advisory.group_package.group]
                issue_type = 'multiple issues' if len(issue_types) > 1 else next(iter(issue_types))
                advisory.advisory_type = issue_type

    if db.session.is_modified(cve):
        flash('Edited {}'.format(cve.id))

    db.session.commit()
    return redirect('/{}'.format(cve.id))
Exemplo n.º 5
0
def todo():
    incomplete_advisories = (db.session.query(Advisory, CVEGroupPackage, CVEGroup)
                             .join(CVEGroupPackage).join(CVEGroup)
                             .filter(and_(
                                 Advisory.publication == Publication.published,
                                 or_(Advisory.content == '', Advisory.content.is_(None),
                                     Advisory.reference == '', Advisory.reference.is_(None))))
                             .group_by(CVEGroupPackage.id)
                             .order_by(Advisory.created.desc())).all()

    scheduled_advisories = (db.session.query(Advisory, CVEGroupPackage, CVEGroup)
                            .join(CVEGroupPackage).join(CVEGroup)
                            .filter(Advisory.publication == Publication.scheduled)
                            .group_by(CVEGroupPackage.id)
                            .order_by(Advisory.created.desc())).all()

    unhandled_advisories = (db.session.query(CVEGroup, func.group_concat(CVEGroupPackage.pkgname, ' '))
                            .join(CVEGroupPackage)
                            .outerjoin(Advisory)
                            .filter(CVEGroup.advisory_qualified)
                            .filter(CVEGroup.status == Status.fixed)
                            .group_by(CVEGroup.id)
                            .having(func.count(Advisory.id) == 0)
                            .order_by(CVEGroup.id)).all()
    for index, item in enumerate(unhandled_advisories):
        unhandled_advisories[index] = (item[0], item[1].split(' '))
    unhandled_advisories = sorted(unhandled_advisories, key=lambda item: item[0].id)
    unhandled_advisories = sorted(unhandled_advisories, key=lambda item: item[0].severity)

    unknown_issues = (db.session.query(CVE)
                      .filter(or_(CVE.remote == Remote.unknown,
                                  CVE.severity == Severity.unknown,
                                  CVE.description.is_(None),
                                  CVE.description == '',
                                  CVE.issue_type.is_(None),
                                  CVE.issue_type == 'unknown'))
                      .order_by(CVE.id.desc())).all()

    unknown_groups = CVEGroup.query.filter(CVEGroup.status == Status.unknown).all()
    unknown_groups = (db.session.query(CVEGroup, Package)
                        .join(CVEGroupPackage).join(Package, Package.name == CVEGroupPackage.pkgname)
                        .filter(CVEGroup.status == Status.unknown)
                        .group_by(CVEGroupPackage.id)
                        .order_by(CVEGroup.created.desc())).all()

    unknown_groups_data = defaultdict(list)
    for group, package in unknown_groups:
        unknown_groups_data[group].append(package)
    unknown_groups = []
    for group, packages in unknown_groups_data.items():
        unknown_groups.append((group, packages))
    unknown_groups = sorted(unknown_groups, key=lambda item: item[0].id)

    vulnerable_groups = (db.session.query(CVEGroup, Package)
                         .join(CVEGroupPackage).join(Package, Package.name == CVEGroupPackage.pkgname)
                         .filter(CVEGroup.status == Status.vulnerable)
                         .filter(or_(CVEGroup.fixed is None, CVEGroup.fixed == ''))
                         .group_by(CVEGroup.id).group_by(Package.name, Package.version)
                         .order_by(CVEGroup.created.desc())).all()

    vulnerable_group_data = defaultdict(list)
    for group, package in vulnerable_groups:
        vulnerable_group_data[group].append(package)

    bumped_groups = []
    for group, packages in vulnerable_group_data.items():
        packages = sorted(packages, key=cmp_to_key(vercmp, attrgetter('version')), reverse=True)
        if 0 == vercmp(group.affected, packages[0].version):
            continue
        versions = filter_duplicate_packages(packages, filter_arch=True)
        pkgnames = set([pkg.name for pkg in packages])
        bumped_groups.append((group, pkgnames, versions))
    bumped_groups = sorted(bumped_groups, key=lambda item: item[0].id, reverse=True)
    bumped_groups = sorted(bumped_groups, key=lambda item: item[0].severity)

    orphan_issues = (db.session.query(CVE)
                       .outerjoin(CVEGroupEntry)
                       .group_by(CVE.id)
                       .having(func.count(CVEGroupEntry.id) == 0)
                       .order_by(CVE.id)).all()

    entries = {
        'scheduled_advisories': scheduled_advisories,
        'incomplete_advisories': incomplete_advisories,
        'unhandled_advisories': unhandled_advisories,
        'unknown_issues': unknown_issues,
        'unknown_groups': unknown_groups,
        'bumped_groups': bumped_groups,
        'orphan_issues': orphan_issues
    }
    return render_template('todo.html',
                           title='Todo Lists',
                           entries=entries,
                           smiley=smileys_happy[randint(0, len(smileys_happy) - 1)],
                           can_handle_advisory=user_can_handle_advisory(),
                           can_edit_group=user_can_edit_group(),
                           can_edit_issue=user_can_edit_issue())
Exemplo n.º 6
0
def edit_cve(cve):
    entries = (db.session.query(
        CVE, CVEGroup, Advisory).filter(CVE.id == cve).outerjoin(
            CVEGroupEntry, CVEGroupEntry.cve_id == CVE.id).outerjoin(
                CVEGroup, CVEGroupEntry.group).outerjoin(
                    CVEGroupPackage, CVEGroup.packages).outerjoin(
                        Advisory,
                        Advisory.group_package_id == CVEGroupPackage.id)
               ).all()
    if not entries:
        return not_found()

    cve: CVE = entries[0][0]
    groups = set(group for (cve, group, advisory) in entries if group)
    advisories = set(advisory for (cve, group, advisory) in entries
                     if advisory)

    if not user_can_edit_issue(advisories):
        flash(ERROR_ISSUE_REFERENCED_BY_ADVISORY.format(cve.id), 'error')
        return forbidden()

    form = CVEForm(edit=True)
    if not form.is_submitted():
        form.cve.data = cve.id
        form.issue_type.data = cve.issue_type
        form.description.data = cve.description
        form.severity.data = cve.severity.name
        form.remote.data = cve.remote.name
        form.reference.data = cve.reference
        form.notes.data = cve.notes
        form.changed.data = str(cve.changed)
        form.changed_latest.data = str(cve.changed)

    concurrent_modification = str(cve.changed) != form.changed.data

    if not form.validate_on_submit() or (
            concurrent_modification
            and not (form.force_submit.data
                     and str(cve.changed) == form.changed_latest.data)):
        if advisories:
            flash(
                'WARNING: This is referenced by an already published advisory!',
                'warning')

        issue = None
        code = 200
        if concurrent_modification:
            flash('WARNING: The remote data has changed!', 'warning')
            code = Conflict.code

            issue = CVE()
            issue.id = form.cve.data
            issue.issue_type = form.issue_type.data
            issue.issue_type_mod = cve.issue_type != issue.issue_type
            issue.description = form.description.data
            issue.description_mod = cve.description != issue.description
            issue.severity = Severity.fromstring(form.severity.data)
            issue.severity_mod = cve.severity != issue.severity
            issue.remote = Remote.fromstring(form.remote.data)
            issue.remote_mod = cve.remote != issue.remote
            issue.reference = form.reference.data
            issue.reference_mod = cve.reference != issue.reference
            issue.notes = form.notes.data
            issue.notes_mod = cve.notes != issue.notes

            if form.changed_latest.data != cve.changed:
                form.force_submit.data = False
            form.changed_latest.data = str(cve.changed)

            Transaction = versioning_manager.transaction_cls
            VersionClassCVE = version_class(CVE)
            version = (db.session.query(
                Transaction, VersionClassCVE).outerjoin(
                    VersionClassCVE,
                    Transaction.id == VersionClassCVE.transaction_id).filter(
                        VersionClassCVE.id == cve.id).order_by(
                            Transaction.issued_at.desc())).first()[1]
            issue.transaction = version.transaction
            issue.operation_type = version.operation_type
            issue.previous = cve

        return render_template(
            'form/cve.html',
            title='Edit {}'.format(cve),
            form=form,
            CVE=CVE,
            issue=issue,
            concurrent_modification=concurrent_modification,
            can_watch_user_log=user_can_watch_user_log()), code

    severity = Severity.fromstring(form.severity.data)
    severity_changed = cve.severity != severity
    issue_type_changed = cve.issue_type != form.issue_type.data

    cve.issue_type = form.issue_type.data
    cve.description = form.description.data
    cve.severity = severity
    cve.remote = Remote.fromstring(form.remote.data)
    cve.reference = form.reference.data
    cve.notes = form.notes.data

    if severity_changed or issue_type_changed:
        # update cached group severity for all goups containing this issue
        group_ids = [group.id for group in groups]
        issues = (db.session.query(
            CVEGroup, CVE).join(CVEGroupEntry, CVEGroup.issues).join(
                CVE, CVEGroupEntry.cve).group_by(CVEGroup.id).group_by(CVE.id))
        if group_ids:
            issues = issues.filter(CVEGroup.id.in_(group_ids))
        issues = (issues).all()

        if severity_changed:
            group_severity = defaultdict(list)
            for group, issue in issues:
                group_severity[group].append(issue.severity)
            for group, severities in group_severity.items():
                group.severity = highest_severity(severities)

        # update scheduled advisories if the issue type changes
        if advisories and issue_type_changed:
            group_issue_type = defaultdict(set)
            for group, issue in issues:
                group_issue_type[group].add(issue.issue_type)
            for advisory in advisories:
                if Publication.published == advisory.publication:
                    continue
                issue_types = group_issue_type[advisory.group_package.group]
                issue_type = 'multiple issues' if len(
                    issue_types) > 1 else next(iter(issue_types))
                advisory.advisory_type = issue_type

    if db.session.is_modified(cve) or severity_changed or issue_type_changed:
        cve.changed = datetime.utcnow()
        flash('Edited {}'.format(cve.id))

    db.session.commit()
    return redirect('/{}'.format(cve.id))