Пример #1
0
def publish_advisory(asa):
    advisory = (db.session.query(Advisory)
                .filter(Advisory.id == asa)
                ).first()
    if not advisory:
        return not_found()

    if advisory.publication == Publication.published:
        return redirect('/{}'.format(asa))

    form = AdvisoryPublishForm(advisory.id)
    if not form.is_submitted():
        form.reference.data = advisory.reference
        if not advisory.reference:
            form.reference.data = advisory_fetch_reference_url_from_mailman(advisory)
    if not form.validate_on_submit():
        return render_template('form/publish.html',
                               title='Publish {}'.format(advisory.id),
                               Advisory=Advisory,
                               form=form)

    if advisory.reference != form.reference.data:
        advisory.content = form.advisory_content
        advisory_extend_model_from_advisory_text(advisory)
    advisory.reference = form.reference.data
    advisory.publication = Publication.published
    db.session.commit()

    flash('Published {}'.format(advisory.id))
    return redirect('/advisory')
Пример #2
0
def edit_advisory(advisory_id):
    advisory = db.get(Advisory, id=advisory_id)
    if not advisory:
        return not_found()

    form = AdvisoryEditForm(advisory.id)
    if not form.is_submitted():
        form.workaround.data = advisory.workaround
        form.impact.data = advisory.impact
        form.reference.data = advisory.reference
        if not advisory.reference and Publication.published == advisory.publication:
            form.reference.data = advisory_fetch_reference_url_from_mailman(advisory)
    if not form.validate_on_submit():
        if advisory.reference:
            flash(WARNING_ADVISORY_ALREADY_PUBLISHED, 'warning')
        return render_template('form/advisory.html',
                               title='Edit {}'.format(advisory.id),
                               Advisory=Advisory,
                               form=form)

    advisory.impact = form.impact.data or None
    advisory.workaround = form.workaround.data or None
    if advisory.reference != form.reference.data:
        advisory.content = form.advisory_content
        advisory_extend_model_from_advisory_text(advisory)
    advisory.reference = form.reference.data or None
    db.session.commit()

    flash('Edited {}'.format(advisory.id))
    return redirect('/{}'.format(advisory.id))
Пример #3
0
def show_cve_json(cve, path=None, suffix=None):
    data = get_cve_data(cve)
    if not data:
        return not_found(json=True)

    cve = data['issue']
    references = cve.reference.replace(
        '\r', '').split('\n') if cve.reference else []
    packages = list(
        set(
            sorted([
                item for sublist in data['group_packages'].values()
                for item in sublist
            ])))
    advisories = data['advisories']
    if not current_user.role.is_reporter:
        advisories = list(
            filter(
                lambda advisory: advisory.publication == Publication.published,
                advisories))

    json_data = OrderedDict()
    json_data['name'] = cve.id
    json_data['type'] = cve.issue_type
    json_data['severity'] = cve.severity.label
    json_data['vector'] = cve.remote.label
    json_data['description'] = cve.description
    json_data['groups'] = [str(group) for group in data['groups']]
    json_data['packages'] = packages
    json_data['advisories'] = [advisory.id for advisory in advisories]
    json_data['references'] = references
    json_data['notes'] = cve.notes if cve.notes else None
    return json_data
Пример #4
0
def delete_user(username):
    user = User.query.filter_by(name=username).first()
    if not user:
        return not_found()

    form = ConfirmForm()
    title = 'Delete {}'.format(username)
    if not form.validate_on_submit():
        return render_template('admin/form/delete_user.html',
                               title=title,
                               heading=title,
                               form=form,
                               user=user)

    if not form.confirm.data:
        return redirect('/user')

    active_admins = User.query.filter_by(active=True,
                                         role=UserRole.administrator).count()
    if user.id == current_user.id and 1 >= active_admins:
        return forbidden()

    user_invalidate(user)
    db.session.delete(user)
    db.session.commit()
    flash('Deleted user {}'.format(user.name))
    return redirect('/user')
Пример #5
0
def show_generated_advisory(advisory_id, raw=False):
    entries = (db.session.query(Advisory, CVEGroup, CVEGroupPackage, CVE)
               .filter(Advisory.id == advisory_id)
               .join(CVEGroupPackage).join(CVEGroup).join(CVEGroupEntry).join(CVE)
               .order_by(CVE.id)
               ).all()
    if not entries:
        return not_found()

    advisory = entries[0][0]
    group = entries[0][1]
    package = entries[0][2]
    issues = sorted([issue for (advisory, group, package, issue) in entries])
    severity_sorted_issues = sorted(issues, key=lambda issue: issue.issue_type)
    severity_sorted_issues = sorted(severity_sorted_issues, key=lambda issue: issue.severity)

    remote = any([issue.remote is Remote.remote for issue in issues])
    issues_listing_formatted = (('\n{}'.format(' ' * len('CVE-ID  : ')))
                                .join(list(map(' '.join, chunks([issue.id for issue in issues], 4)))))
    link = TRACKER_ADVISORY_URL.format(advisory.id, group.id)
    upstream_released = group.affected.split('-')[0].split('+')[0] != group.fixed.split('-')[0].split('+')[0]
    upstream_version = group.fixed.split('-')[0].split('+')[0]
    if ':' in upstream_version:
        upstream_version = upstream_version[upstream_version.index(':') + 1:]
    unique_issue_types = []
    for issue in severity_sorted_issues:
        if issue.issue_type not in unique_issue_types:
            unique_issue_types.append(issue.issue_type)

    references = []
    if group.bug_ticket:
        references.append(TRACKER_BUGTRACKER_URL.format(group.bug_ticket))
    references.extend([ref for ref in multiline_to_list(group.reference)
                       if ref not in references])
    list(map(lambda issue: references.extend(
        [ref for ref in multiline_to_list(issue.reference) if ref not in references]), issues))

    raw_asa = render_template('advisory.txt',
                              advisory=advisory,
                              group=group,
                              package=package,
                              issues=issues,
                              remote=remote,
                              issues_listing_formatted=issues_listing_formatted,
                              link=link,
                              workaround=advisory.workaround,
                              impact=advisory.impact,
                              upstream_released=upstream_released,
                              upstream_version=upstream_version,
                              unique_issue_types=unique_issue_types,
                              references=references,
                              TRACKER_ISSUE_URL=TRACKER_ISSUE_URL,
                              TRACKER_GROUP_URL=TRACKER_GROUP_URL)
    if raw:
        return raw_asa

    raw_asa = '\n'.join(raw_asa.split('\n')[2:])
    raw_asa = str(escape(raw_asa))
    raw_asa = advisory_extend_html(raw_asa, issues, package)
    return render_html_advisory(advisory=advisory, package=package, group=group, raw_asa=raw_asa, generated=True)
Пример #6
0
def show_group(avg):
    data = get_group_data(avg)
    if not data:
        return not_found()

    group = data['group']
    advisories = data['advisories']
    if not current_user.role.is_reporter:
        advisories = list(filter(lambda advisory: advisory.publication == Publication.published, advisories))
    issues = data['issues']
    packages = data['packages']
    issue_types = data['issue_types']
    versions = data['versions']
    issue_type = 'multiple issues' if len(issue_types) > 1 else issue_types[0]
    pkgnames = list(set(sorted([pkg.pkgname for pkg in packages])))

    form = AdvisoryForm()
    form.advisory_type.data = issue_type

    return render_template('group.html',
                           title='{} - {}'.format(group, ' '.join(pkgnames)),
                           form=form,
                           group=group,
                           packages=packages,
                           issues=issues,
                           advisories=advisories,
                           versions=versions,
                           Status=Status,
                           issue_type=issue_type,
                           bug_data=get_bug_data(issues, packages, versions, group),
                           advisories_pending=data['advisories_pending'],
                           can_edit=user_can_edit_group(advisories),
                           can_delete=user_can_delete_group(advisories),
                           can_handle_advisory=user_can_handle_advisory())
Пример #7
0
def delete_advisory(advisory_id):
    advisory, pkg, group = (db.session.query(Advisory, CVEGroupPackage, CVEGroup)
                            .filter(Advisory.id == advisory_id)
                            .join(CVEGroupPackage).join(CVEGroup)).first()

    if not advisory:
        return not_found()

    if Publication.scheduled != advisory.publication:
        return forbidden()

    form = ConfirmForm()
    title = 'Delete {}'.format(advisory.id)
    if not form.validate_on_submit():
        return render_template('form/delete_advisory.html',
                               title=title,
                               heading=title,
                               form=form,
                               advisory=advisory,
                               pkg=pkg,
                               group=group)

    if not form.confirm.data:
        return redirect('/{}'.format(advisory.id))

    db.session.delete(advisory)
    db.session.commit()
    flash('Deleted {}'.format(advisory.id))
    return redirect('/')
Пример #8
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))
Пример #9
0
def show_group_json(avg, postfix=None):
    data = get_group_data(avg)
    if not data:
        return not_found(json=True)

    group = data['group']
    advisories = data['advisories']
    if not current_user.role.is_reporter:
        advisories = list(
            filter(
                lambda advisory: advisory.publication == Publication.published,
                advisories))
    issues = data['issues']
    packages = data['packages']
    issue_types = data['issue_types']
    references = group.reference.replace(
        '\r', '').split('\n') if group.reference else []

    json_data = OrderedDict()
    json_data['name'] = group.name
    json_data['packages'] = [package.pkgname for package in packages]
    json_data['status'] = group.status.label
    json_data['severity'] = group.severity.label
    json_data['type'] = 'multiple issues' if len(
        issue_types) > 1 else issue_types[0]
    json_data['affected'] = group.affected
    json_data['fixed'] = group.fixed if group.fixed else None
    json_data['ticket'] = group.bug_ticket if group.bug_ticket else None
    json_data['issues'] = [str(cve) for cve in issues]
    json_data['advisories'] = [advisory.id for advisory in advisories]
    json_data['references'] = references
    json_data['notes'] = group.notes if group.notes else None

    return json_data
Пример #10
0
def copy_group(avg):
    group_id = avg.replace('AVG-', '')
    group_data = (db.session.query(
        CVEGroup, CVE, func.group_concat(
            CVEGroupPackage.pkgname,
            ' ')).filter(CVEGroup.id == group_id).join(CVEGroupEntry).join(
                CVE).join(CVEGroupPackage).group_by(CVEGroup.id).group_by(
                    CVE.id).order_by(CVE.id)).all()
    if not group_data:
        return not_found()

    group = group_data[0][0]
    issues = [cve for (group, cve, pkg) in group_data]
    issue_ids = [cve.id for cve in issues]
    pkgnames = set(
        chain.from_iterable(
            [pkg.split(' ') for (group, cve, pkg) in group_data]))

    form = GroupForm()
    form.advisory_qualified.data = group.advisory_qualified
    form.affected.data = group.affected
    form.bug_ticket.data = group.bug_ticket
    form.cve.data = '\n'.join(issue_ids)
    form.fixed.data = group.fixed
    form.notes.data = group.notes
    form.pkgnames.data = '\n'.join(sorted(pkgnames))
    form.reference.data = group.reference
    form.status.data = status_to_affected(group.status).name

    return render_template('form/group.html',
                           title='Add AVG',
                           form=form,
                           CVEGroup=CVEGroup,
                           action='/avg/add')
Пример #11
0
def show_advisory(advisory_id, raw=False):
    entries = (db.session.query(
        Advisory, CVEGroup, CVEGroupPackage,
        CVE).filter(Advisory.id == advisory_id).join(CVEGroupPackage).join(
            CVEGroup).join(CVEGroupEntry).join(CVE).order_by(CVE.id)).all()
    if not entries:
        return not_found()

    advisory = entries[0][0]
    group = entries[0][1]
    package = entries[0][2]
    issues = [issue for (advisory, group, package, issue) in entries]

    if not advisory.content:
        if raw:
            return redirect('/{}/generate/raw'.format(advisory_id))
        return redirect('/{}/generate'.format(advisory_id))

    if raw:
        return advisory.content
    asa = advisory_extend_html(advisory.content, issues, package)
    return render_html_advisory(advisory=advisory,
                                package=package,
                                group=group,
                                raw_asa=asa,
                                generated=False)
Пример #12
0
def show_advisory_log(advisory_id, path=None):
    advisory = (db.session.query(Advisory).filter(
        Advisory.id == advisory_id)).first()
    if not advisory:
        return not_found()

    return render_template('log/advisory_log.html',
                           title='{} - log'.format(advisory_id),
                           advisory=advisory,
                           can_watch_user_log=user_can_watch_user_log())
Пример #13
0
def schedule_advisory(avg):
    avg_id = avg.replace('AVG-', '')
    form = AdvisoryForm()

    if not form.validate_on_submit():
        flash('Form validation failed', 'error')
        return redirect('/{}'.format(avg))

    entries = (db.session.query(
        CVEGroup, CVE,
        CVEGroupPackage, Advisory).filter(CVEGroup.id == avg_id).join(
            CVEGroupEntry, CVEGroup.issues).join(CVE, CVEGroupEntry.cve).join(
                CVEGroupPackage, CVEGroup.packages).outerjoin(
                    Advisory,
                    and_(Advisory.group_package_id == CVEGroupPackage.id))
               ).all()
    if not entries:
        return not_found()

    pkgs = set()
    advisories = set()
    for group_entry, cve, pkg, advisory in entries:
        pkgs.add(pkg)
        if advisory:
            advisories.add(advisory)

    if Status.fixed != group_entry.status:
        flash(ERROR_ADVISORY_GROUP_NOT_FIXED, 'error')
        return redirect('/{}'.format(avg))

    if 0 < len(advisories):
        flash(ERROR_ADVISORY_ALREADY_EXISTS, 'error')
        return redirect('/{}'.format(avg))

    last_advisory_date = advisory_get_date_label()
    last_advisory_num = 0
    last_advisory = (db.session.query(Advisory).order_by(
        Advisory.created.desc()).limit(1)).first()
    if last_advisory:
        m = match(advisory_regex, last_advisory.id)
        if last_advisory_date == m.group(2):
            last_advisory_num = int(m.group(3))

    for pkg in pkgs:
        last_advisory_num += 1
        asa = advisory_get_label(last_advisory_date, last_advisory_num)
        db.create(Advisory,
                  id=asa,
                  advisory_type=form.advisory_type.data,
                  publication=Publication.scheduled,
                  group_package=pkg)
    db.session.commit()

    flash('Scheduled {}'.format(asa))
    return redirect('/{}'.format(asa))
Пример #14
0
def show_cve_log(cve, path=None):
    data = get_cve_data(cve)
    if not data:
        return not_found()

    title = '{} - log'.format(data['issue'].id)

    return render_template('log/cve_log.html',
                           title=title,
                           issue=data['issue'],
                           can_watch_user_log=user_can_watch_user_log())
Пример #15
0
def show_package_json(pkgname, suffix=None):
    data = get_package_data(pkgname)
    if not data:
        return not_found(json=True)

    advisories = data['advisories']
    versions = data['versions']
    groups = data['groups']
    issues = data['issues']

    json_advisory = []
    for advisory in advisories:
        entry = OrderedDict()
        entry['name'] = advisory.id
        entry['date'] = advisory.created.strftime('%Y-%m-%d')
        entry['severity'] = advisory.group_package.group.severity.label
        entry['type'] = advisory.advisory_type
        entry['reference'] = advisory.reference if advisory.reference else None
        json_advisory.append(entry)

    json_versions = []
    for version in versions:
        entry = OrderedDict()
        entry['version'] = version.version
        entry['database'] = version.database
        json_versions.append(entry)

    json_groups = []
    for group in groups:
        entry = OrderedDict()
        entry['name'] = group.name
        entry['status'] = group.status.label
        entry['severity'] = group.severity.label
        json_groups.append(entry)

    json_issues = []
    for issue in issues:
        group = issue['group']
        issue = issue['issue']
        entry = OrderedDict()
        entry['name'] = issue.id
        entry['severity'] = issue.severity.label
        entry['type'] = issue.issue_type
        entry['status'] = group.status.label
        json_issues.append(entry)

    json_data = OrderedDict()
    json_data['name'] = pkgname
    json_data['versions'] = json_versions
    json_data['advisories'] = json_advisory
    json_data['groups'] = json_groups
    json_data['issues'] = json_issues
    return json_data
Пример #16
0
def show_group_log(avg):
    data = get_group_data(avg)
    if not data:
        return not_found(json=True)

    group = data['group']

    return render_template('log/group_log.html',
                           title='{} - log'.format(group),
                           group=group,
                           Status=Status,
                           advisories_pending=data['advisories_pending'],
                           can_watch_user_log=user_can_watch_user_log())
Пример #17
0
def edit_user(username):
    own_user = username == current_user.name
    if not current_user.role.is_administrator and not own_user:
        forbidden()

    user = User.query.filter_by(name=username).first()
    if not user:
        return not_found()

    form = UserForm(edit=True)
    if not form.is_submitted():
        form.username.data = user.name
        form.email.data = user.email
        form.role.data = user.role.name
        form.active.data = user.active
    if not form.validate_on_submit():
        return render_template('admin/form/user.html',
                               title='Edit {}'.format(username),
                               form=form,
                               User=User,
                               random_password=True,
                               password_length={
                                   'min': TRACKER_PASSWORD_LENGTH_MIN,
                                   'max': TRACKER_PASSWORD_LENGTH_MAX
                               })

    active_admins = User.query.filter_by(active=True,
                                         role=UserRole.administrator).count()
    if user.id == current_user.id and 1 == active_admins and not form.active.data:
        return forbidden()

    user.name = form.username.data
    user.email = form.email.data
    user.role = UserRole.fromstring(form.role.data)
    if form.random_password.data:
        form.password.data = random_string()
    if form.password.data and 0 != len(form.password.data):
        user.salt = random_string()
        user.password = hash_password(form.password.data, user.salt)
    user.active = form.active.data
    user_invalidate(user)
    db.session.commit()

    flash_password = ''
    if form.random_password.data:
        flash_password = '******'.format(form.password.data)
    flash('Edited user {}{}'.format(user.name, flash_password))
    return redirect('/user')
Пример #18
0
def show_package(pkgname):
    data = get_package_data(pkgname)
    if not data:
        return not_found()

    groups = data['groups']
    data['groups'] = {'open': list(filter(lambda group: group.status.open(), groups)),
                      'resolved': list(filter(lambda group: group.status.resolved(), groups))}

    issues = data['issues']
    data['issues'] = {'open': list(filter(lambda issue: issue['group'].status.open(), issues)),
                      'resolved': list(filter(lambda issue: issue['group'].status.resolved(), issues))}

    return render_template('package.html',
                           title='{}'.format(pkgname),
                           package=data)
Пример #19
0
def delete_group(avg):
    avg_id = avg.replace('AVG-', '')
    entries = (db.session.query(
        CVEGroup, CVE,
        CVEGroupPackage, Advisory).filter(CVEGroup.id == avg_id).join(
            CVEGroupEntry, CVEGroup.issues).join(CVE, CVEGroupEntry.cve).join(
                CVEGroupPackage, CVEGroup.packages).outerjoin(
                    Advisory,
                    Advisory.group_package_id == CVEGroupPackage.id)).all()
    if not entries:
        return not_found()

    group = entries[0][0]
    issues = set()
    packages = set()
    advisories = set()
    for group, issue, pkg, advisory in entries:
        issues.add(issue)
        packages.add(pkg)
        if advisory:
            advisories.add(advisory)

    if not user_can_delete_group(advisories):
        return forbidden()

    issues = sorted(issues, key=lambda item: item.id)
    packages = sorted(packages, key=lambda item: item.pkgname)
    advisories = sorted(advisories, key=lambda item: item.id, reverse=True)

    form = ConfirmForm()
    title = 'Delete {}'.format(avg)
    if not form.validate_on_submit():
        return render_template('form/delete_group.html',
                               title=title,
                               heading=title,
                               form=form,
                               group=group,
                               issues=issues,
                               packages=packages)

    if not form.confirm.data:
        return redirect('/{}'.format(group))

    db.session.delete(group)
    db.session.commit()
    flash('Deleted {}'.format(group))
    return redirect('/')
Пример #20
0
def copy_issue(issue):
    cve = db.get(CVE, id=issue)
    if not cve:
        return not_found()

    form = CVEForm()
    form.cve.data = cve.id
    form.description.data = cve.description
    form.issue_type.data = cve.issue_type
    form.notes.data = cve.notes
    form.reference.data = cve.reference
    form.remote.data = cve.remote.name
    form.severity.data = cve.severity.name

    return render_template('form/cve.html',
                           title='Add CVE',
                           form=form,
                           CVE=CVE,
                           action='/cve/add')
Пример #21
0
def advisory_atom():
    return not_found()

    last_recent_entries = 15
    data = get_advisory_data()['published'][:last_recent_entries]
    # TODO:fix me
    feed = AtomFeed('Arch Linux Security - Recent advisories',
                    feed_url=request.url, url=request.url_root)

    for entry in data:
        advisory = entry['advisory']
        package = entry['package']
        title = '[{}] {}: {}'.format(advisory.id, package.pkgname, advisory.advisory_type)

        feed.add(title=title,
                 content=render_template('feed.html', content=advisory.content),
                 content_type='html',
                 summary=render_template('feed.html', content=advisory.impact),
                 summary_tpe='html',
                 author='Arch Linux Security Team',
                 url=TRACKER_ISSUE_URL.format(advisory.id),
                 published=advisory.created,
                 updated=advisory.created)
    return feed.get_response()
Пример #22
0
def edit_group(avg):
    group_id = avg.replace('AVG-', '')
    group_data = (db.session.query(CVEGroup, CVE, func.group_concat(CVEGroupPackage.pkgname, ' '), Advisory)
                  .filter(CVEGroup.id == group_id)
                  .join(CVEGroupEntry, CVEGroup.issues)
                  .join(CVE, CVEGroupEntry.cve)
                  .join(CVEGroupPackage, CVEGroup.packages)
                  .outerjoin(Advisory, Advisory.group_package_id == CVEGroupPackage.id)
                  .group_by(CVEGroup.id).group_by(CVE.id).group_by(CVEGroupPackage.pkgname)
                  .order_by(CVE.id)).all()
    if not group_data:
        return not_found()

    group = group_data[0][0]
    issues = set([cve for (group, cve, pkg, advisory) in group_data])
    issue_ids = set([cve.id for cve in issues])
    pkgnames = set(chain.from_iterable([pkg.split(' ') for (group, cve, pkg, advisory) in group_data]))
    advisories = set(advisory for (group, cve, pkg, advisory) in group_data if advisory)

    if not user_can_edit_group(advisories):
        return forbidden()

    form = GroupForm(pkgnames)
    if not form.is_submitted():
        form.affected.data = group.affected
        form.fixed.data = group.fixed
        form.pkgnames.data = "\n".join(sorted(pkgnames))
        form.status.data = status_to_affected(group.status).name
        form.reference.data = group.reference
        form.notes.data = group.notes
        form.bug_ticket.data = group.bug_ticket
        form.advisory_qualified.data = group.advisory_qualified and group.status is not Status.not_affected

        issue_ids = sorted(issue_ids, key=issue_to_numeric)
        form.cve.data = "\n".join(issue_ids)
    if not form.validate_on_submit():
        if advisories:
            flash('WARNING: This is referenced by an already published advisory!', 'warning')
        return render_template('form/group.html',
                               title='Edit {}'.format(avg),
                               form=form,
                               CVEGroup=CVEGroup)

    pkgnames_edited = multiline_to_list(form.pkgnames.data)
    group.affected = form.affected.data
    group.fixed = form.fixed.data
    group.status = affected_to_status(Affected.fromstring(form.status.data), pkgnames_edited[0], group.fixed)
    group.bug_ticket = form.bug_ticket.data
    group.reference = form.reference.data
    group.notes = form.notes.data
    group.advisory_qualified = form.advisory_qualified.data and group.status is not Status.not_affected

    cve_ids = multiline_to_list(form.cve.data)
    cve_ids = set(filter(lambda s: s.startswith('CVE-'), cve_ids))
    issues_removed = set(filter(lambda issue: issue not in cve_ids, issue_ids))
    issues_added = set(filter(lambda issue: issue not in issue_ids, cve_ids))
    issues_final = set(filter(lambda issue: issue.id not in issues_removed, issues))
    issues_changed = any(issues_added) or any(issues_removed)

    # remove old issues
    for issue in filter(lambda issue: issue.cve_id in issues_removed, list(group.issues)):
        group.issues.remove(issue)
        flash('Removed {}'.format(issue.cve_id))

    # add new issues
    severities = [issue.severity for issue in list(filter(lambda issue: issue.id not in issues_removed, issues))]
    for cve_id in issues_added:
        # TODO check if we can avoid this by the latter append call
        cve = db.get(CVE, id=cve_id)
        if not cve:
            cve = CVE.new(id=cve_id)
        db.get_or_create(CVEGroupEntry, group=group, cve=cve)
        flash('Added {}'.format(cve.id))

        severities.append(cve.severity)
        issues_final.add(cve)
    group.severity = highest_severity(severities)

    pkgnames_removed = set(filter(lambda pkgname: pkgname not in pkgnames_edited, pkgnames))
    pkgnames_added = set(filter(lambda pkgname: pkgname not in pkgnames, pkgnames_edited))
    pkgnames_changed = any(pkgnames_removed) or any(pkgnames_added)

    # remove old packages
    for pkg in filter(lambda pkg: pkg.pkgname in pkgnames_removed, list(group.packages)):
        group.packages.remove(pkg)
        flash('Removed {}'.format(pkg.pkgname))

    #  add new packages
    for pkgname in pkgnames_added:
        db.get_or_create(CVEGroupPackage, pkgname=pkgname, group=group)
        flash('Added {}'.format(pkgname))

    # update scheduled advisories
    for advisory in advisories:
        if Publication.published == advisory.publication:
            continue
        issue_type = 'multiple issues' if len(set([issue.issue_type for issue in issues_final])) > 1 else next(iter(issues_final)).issue_type
        advisory.advisory_type = issue_type

    # update changed date on modification
    if pkgnames_changed or issues_changed or db.session.is_modified(group):
        group.changed = datetime.utcnow()
        flash('Edited {}'.format(group.name))

    db.session.commit()
    return redirect('/{}'.format(group.name))
Пример #23
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))
Пример #24
0
def edit_advisory(advisory_id):
    advisory: Advisory = db.get(Advisory, id=advisory_id)
    if not advisory:
        return not_found()

    form = AdvisoryEditForm(advisory.id)
    if not form.is_submitted():
        form.workaround.data = advisory.workaround
        form.impact.data = advisory.impact
        form.reference.data = advisory.reference
        if not advisory.reference and Publication.published == advisory.publication:
            form.reference.data = advisory_fetch_reference_url_from_mailman(
                advisory)
        form.changed.data = str(advisory.changed)
        form.changed_latest.data = str(advisory.changed)

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

    if not form.validate_on_submit() or (
            concurrent_modification
            and not (form.force_submit.data
                     and str(advisory.changed) == form.changed_latest.data)):
        if advisory.reference:
            flash(WARNING_ADVISORY_ALREADY_PUBLISHED, 'warning')

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

            advisory_new = Advisory()
            advisory_new.id = form.advisory_id
            advisory_new.workaround = form.workaround.data or None
            advisory_new.workaround_mod = advisory.workaround != advisory_new.workaround
            advisory_new.impact = form.impact.data or None
            advisory_new.impact_mod = advisory.impact != advisory_new.impact
            advisory_new.reference = form.reference.data or None
            advisory_new.reference_mod = advisory.reference != advisory_new.reference

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

            Transaction = versioning_manager.transaction_cls
            VersionClassAdvisory = version_class(Advisory)
            version = (db.session.query(
                Transaction, VersionClassAdvisory).outerjoin(
                    VersionClassAdvisory, Transaction.id ==
                    VersionClassAdvisory.transaction_id).filter(
                        VersionClassAdvisory.id == advisory.id).order_by(
                            Transaction.issued_at.desc())).first()[1]
            advisory_new.transaction = version.transaction
            advisory_new.operation_type = version.operation_type
            advisory_new.previous = advisory

        return render_template(
            'form/advisory.html',
            title='Edit {}'.format(advisory.id),
            Advisory=Advisory,
            advisory=advisory_new,
            form=form,
            concurrent_modification=concurrent_modification,
            can_watch_user_log=user_can_watch_user_log()), code

    advisory.impact = form.impact.data or None
    advisory.workaround = form.workaround.data or None
    if advisory.reference != form.reference.data:
        advisory.content = form.advisory_content
        advisory_extend_model_from_advisory_text(advisory)
    advisory.reference = form.reference.data or None

    # update changed date on modification
    if db.session.is_modified(advisory):
        advisory.changed = datetime.utcnow()
        flash('Edited {}'.format(advisory.id))

    db.session.commit()
    return redirect('/{}'.format(advisory.id))
Пример #25
0
 def decorated_view(*args, **kwargs):
     if SSO_ENABLED is not expected:
         from tracker.view.error import not_found
         return not_found()
     return func(*args, **kwargs)
Пример #26
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))
Пример #27
0
def delete_issue(issue):
    entries = (db.session.query(CVE, CVEGroup, CVEGroupPackage, Advisory)
               .filter(CVE.id == issue)
               .outerjoin(CVEGroupEntry).outerjoin(CVEGroup).outerjoin(CVEGroupPackage)
               .outerjoin(Advisory, Advisory.group_package_id == CVEGroupPackage.id)
               .order_by(CVEGroup.created.desc()).order_by(CVEGroupPackage.pkgname)).all()
    if not entries:
        return not_found()

    issue = entries[0][0]
    advisories = set()
    groups = set()
    group_packages = defaultdict(set)
    for cve, group, pkg, advisory in entries:
        if group:
            groups.add(group)
            group_packages[group].add(pkg.pkgname)
        if advisory:
            advisories.add(advisory)

    if not user_can_delete_issue(advisories):
        return forbidden()

    group_ids = [group.id for group in groups]

    group_entries = (db.session.query(CVEGroup, CVE)
                     .join(CVEGroupEntry).join(CVE)
                     .order_by(CVE.id.desc()))
    if group_ids:
        group_entries = group_entries.filter(CVEGroup.id.in_(group_ids))
    group_entries = group_entries.all()

    group_issues = defaultdict(set)
    for group, cve in group_entries:
        group_issues[group].add(cve)

    groups = sorted(groups, key=lambda item: item.created, reverse=True)
    groups = sorted(groups, key=lambda item: item.status)
    group_packages = dict(map(lambda item: (item[0], sorted(item[1])), group_packages.items()))

    form = ConfirmForm()
    title = 'Delete {}'.format(issue)
    if not form.validate_on_submit():
        return render_template('form/delete_cve.html',
                               title=title,
                               heading=title,
                               form=form,
                               issue=issue,
                               groups=groups,
                               group_packages=group_packages,
                               group_issues=group_issues)

    if not form.confirm.data:
        return redirect('/{}'.format(issue))

    # delete groups that only contain this issue
    for group, issues in group_issues.items():
        if 0 == len(list(filter(lambda e: e.id != issue.id, issues))):
            flash('Deleted {}'.format(group))
            db.session.delete(group)

    db.session.delete(issue)
    db.session.commit()
    flash('Deleted {}'.format(issue))
    return redirect('/')