Beispiel #1
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))
Beispiel #2
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))
Beispiel #3
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))