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 ]))) 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 data['advisories']] json_data['references'] = references json_data['notes'] = cve.notes if cve.notes else None return json_data
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')
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'] 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
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)
def show_group(avg): data = get_group_data(avg) if not data: return not_found() group = data['group'] advisories = data['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] form = AdvisoryForm() form.advisory_type.data = issue_type return render_template('group.html', title='{}'.format(group), 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), advisory_pending=data['advisory_pending'], can_edit=user_can_edit_group(advisories), can_delete=user_can_delete_group(advisories), can_handle_advisory=user_can_handle_advisory())
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')
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')
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('/')
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))
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 = [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)
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
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).join( CVE).join(CVEGroupPackage).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))
def show_cve(cve, path=None): data = get_cve_data(cve) if not data: return not_found() return render_template('cve.html', title=data['issue'].id, issue=data['issue'], groups=data['groups'], group_packages=data['group_packages'], advisories=data['advisories'], can_edit=user_can_edit_issue(data['advisories']), can_delete=user_can_delete_issue( data['advisories']))
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).join( CVE).join(CVEGroupPackage).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 0 < len(advisories): flash('Advisory already exists', 'error') return redirect('/{}'.format(avg)) now = datetime.utcnow().utctimetuple() last_advisory_date = '{}{}'.format(now.tm_year, '{}'.format(now.tm_mon).rjust(2, '0')) 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 = 'ASA-{}-{}'.format(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))
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)
def get_package_data(pkgname): entries = (db.session.query( Package, CVEGroup, CVE, Advisory).filter(Package.name == pkgname).outerjoin( CVEGroupPackage, CVEGroupPackage.pkgname == pkgname).outerjoin( CVEGroup, CVEGroup.id == CVEGroupPackage.group_id).outerjoin( CVEGroupEntry, CVEGroupPackage.group_id == CVEGroupEntry.group_id). outerjoin(CVE, CVE.id == CVEGroupEntry.cve_id).outerjoin( Advisory, and_(Advisory.group_package_id == CVEGroupPackage.id, Advisory.publication == Publication.published))).all() if not entries: return not_found() groups = set() issues = set() advisories = set() versions = set() for package, group, cve, advisory in entries: versions.add(package) if group: groups.add(group) if cve: issues.add((cve, group)) if advisory: advisories.add(advisory) issues = [{'issue': e[0], 'group': e[1]} for e in issues] issues = sorted(issues, key=lambda item: item['issue'].id, reverse=True) issues = sorted(issues, key=lambda item: item['group'].status) groups = sorted(groups, key=lambda item: item.id, reverse=True) groups = sorted(groups, key=lambda item: item.status) advisories = sorted(advisories, key=lambda item: item.id, reverse=True) versions = sort_packages(filter_duplicate_packages(list(versions), True)) package = versions[0] if versions else None return { 'package': package, 'pkgname': pkgname, 'versions': versions, 'groups': groups, 'issues': issues, 'advisories': advisories }
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 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')
def delete_group(avg): avg_id = avg.replace('AVG-', '') entries = (db.session.query(CVEGroup, CVE, CVEGroupPackage, Advisory) .filter(CVEGroup.id == avg_id) .join(CVEGroupEntry).join(CVE).join(CVEGroupPackage) .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('/')
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) return render_template('cve.html', title=title, issue=data['issue'], groups=data['groups'], group_packages=data['group_packages'], advisories=data['advisories'], can_edit=user_can_edit_issue(data['advisories']), can_delete=user_can_delete_issue(data['advisories']))
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')
def edit_cve(cve): entries = (db.session.query( CVE, CVEGroup, Advisory).filter(CVE.id == cve).outerjoin(CVEGroupEntry).outerjoin( CVEGroup).outerjoin(CVEGroupPackage).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).join(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 db.session.commit() flash('Edited {}'.format(cve.id)) return redirect('/{}'.format(cve.id))
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('/')
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).join( CVE).join(CVEGroupPackage).outerjoin( Advisory, Advisory.group_package_id == CVEGroupPackage.id).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, advisory) in group_data] issue_ids = [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 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)) if issues_removed: (db.session.query(CVEGroupEntry).filter( CVEGroupEntry.group_id == group.id).filter( CVEGroupEntry.cve_id.in_(issues_removed)).delete( synchronize_session=False)) for removed in issues_removed: flash('Removed {}'.format(removed)) severities = [ issue.severity for issue in list( filter(lambda issue: issue.id not in issues_removed, issues)) ] for cve_id in issues_added: cve = db.get_or_create(CVE, id=cve_id) db.get_or_create(CVEGroupEntry, group=group, cve=cve) severities.append(cve.severity) issues_final.add(cve) flash('Added {}'.format(cve.id)) 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)) if pkgnames_removed: (db.session.query(CVEGroupPackage).filter( CVEGroupPackage.group_id == group.id).filter( CVEGroupPackage.pkgname.in_(pkgnames_removed)).delete( synchronize_session=False)) for removed in pkgnames_removed: flash('Removed {}'.format(removed)) 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 db.session.commit() flash('Edited {}'.format(group.name)) return redirect('/{}'.format(group.name))