def embed(vcdb_id): try: section_id = int(request.args.get("sid", -1)) start_line = int(request.args.get("start_line", 1)) end_line = int(request.args.get("end_line", -1)) vulnerability_details = VulnerabilityDetails(vcdb_id) vulnerability_details.validate_and_simplify_id() view = vulnerability_details.vulnerability_view if not view: return make_response(("No vulnerability found", 404)) if not view.master_commit: return make_response( (f"Vuln (id: {view.id}) has no linked Git commits!", 404) ) master_commit = vulnerability_details.get_master_commit() files_schema = RepositoryFilesSchema(many=True) # Hack to quickly retrieve the full data. custom_data = json.loads( files_schema.jsonify(master_commit.repository_files).data ) settings = { "section_id": section_id, "startLine": start_line, "endLine": end_line, "entry_data": custom_data, } return render_template( "vulnerability/embedded.html", vulnerability_details=vulnerability_details, embed_settings=settings, ) except (ValueError, InvalidIdentifierException): return make_response(("No vulnerability found", 404))
def view_vuln(vuln_id, use_template): try: vulnerability_details = VulnerabilityDetails(vuln_id) vulnerability_details.validate() except InvalidIdentifierException as err: return flashError(str(err), "serve_index") return render_template( use_template, vulnerability_details=vulnerability_details)
def view_vuln(vcdb_id, use_template): try: vulnerability_details = VulnerabilityDetails(vcdb_id) vulnerability_details.validate_and_simplify_id() if not vulnerability_details.vulnerability_view: abort(404) except InvalidIdentifierException as err: return flash_error(str(err), "frontend.serve_index") return render_template(use_template, vulnerability_details=vulnerability_details)
def _get_vulnerability_details(vuln_id): try: vulnerability_details = VulnerabilityDetails(vuln_id) vulnerability_details.validate() # Drop everything else. if not vulnerability_details.vulnerability_view: abort(404) return vulnerability_details except InvalidIdentifierException: abort(404)
def _create_vuln_internal(vcdb_id=None): try: vulnerability_details = VulnerabilityDetails(vcdb_id) vulnerability = vulnerability_details.get_or_create_vulnerability() except InvalidIdentifierException as err: return flash_error(str(err), "frontend.serve_index") if vulnerability.id: logging.debug("Preexisting vulnerability entry found: %r", vulnerability.id) delete_form = VulnerabilityDeleteForm() if delete_form.validate_on_submit(): db.session.delete(vulnerability) # Remove the entry. db.session.commit() flash("The entry was deleted.", "success") return redirect("/") form = VulnerabilityDetailsForm(obj=vulnerability) commit = form.data["commits"][0] if not commit["repo_name"]: logging.info("Empty repository name. %r", commit) repo_url = commit["repo_url"] vcs_handler = get_vcs_handler(None, repo_url) if vcs_handler: logging.info("Found name. %r", vcs_handler.repo_name) form.commits[0].repo_name.process_data(vcs_handler.repo_name) if form.validate_on_submit(): try: form.populate_obj(vulnerability) db.session.add(vulnerability) db.session.commit() # TODO: Improve this hack to assign a new vcdb_id here. # Currently, we are just piggy backing on the auto increment # of the primary key to ensure uniqueness. # This will likely be prone to race conditions. vulnerability.vcdb_id = vulnerability.id db.session.add(vulnerability) db.session.commit() logging.debug("Successfully created/updated entry: %r", vulnerability.id) flash("Successfully created/updated entry.", "success") return redirect( url_for("vuln.vuln_view", vcdb_id=vulnerability.vcdb_id)) except InvalidIdentifierException as err: flash_error(str(err)) return render_template( "vulnerability/create.html", vulnerability_details=vulnerability_details, form=form, )
def _get_vulnerability_details(vcdb_id, vuln_id=None, simplify_id: bool = True): try: vulnerability_details = VulnerabilityDetails(vcdb_id, vuln_id) if simplify_id: vulnerability_details.validate_and_simplify_id() # Drop everything else. if not vulnerability_details.vulnerability_view: abort(404) return vulnerability_details except InvalidIdentifierException: abort(404)
def get_vulnerability_details(vcdb_id, vuln_id=None, simplify_id: bool = True): # pylint: disable=import-outside-toplevel,cyclic-import from app.vulnerability.views.details import VulnerabilityDetails # pylint: enable=import-outside-toplevel,cyclic-import try: vulnerability_details = VulnerabilityDetails(vcdb_id, vuln_id) if simplify_id: vulnerability_details.validate_and_simplify_id() # Drop everything else. if not vulnerability_details.vulnerability_view: abort(404) return vulnerability_details except InvalidIdentifierException: abort(404)
def _create_vuln_internal(vuln_id=None): try: vulnerability_details = VulnerabilityDetails(vuln_id) vulnerability = vulnerability_details.get_or_create_vulnerability() except InvalidIdentifierException as err: return flashError(str(err), "serve_index") if vulnerability.id: logging.debug("Preexisting vulnerability entry found: %s", vulnerability.id) delete_form = VulnerabilityDeleteForm() if delete_form.validate_on_submit(): db.session.delete(vulnerability) # Remove the entry. db.session.commit() flash("The entry was deleted.", "success") return redirect("/") form = VulnerabilityDetailsForm(obj=vulnerability) commit = form.data["commits"][0] if not commit["repo_name"]: logging.info("Empty repository name. %r", commit) repo_url = commit["repo_url"] vcs_handler = get_vcs_handler(None, repo_url) if vcs_handler: logging.info("Found name. %r", vcs_handler.repo_name) form.commits[0].repo_name.process_data(vcs_handler.repo_name) if form.validate_on_submit(): try: form.populate_obj(vulnerability) db.session.add(vulnerability) db.session.commit() logging.debug("Successfully created/updated entry: %s", vulnerability.id) flash("Successfully created/updated entry.", "success") return redirect(url_for("vuln.vuln_view", vuln_id=vulnerability.id)) except InvalidIdentifierException as err: flashError(str(err)) return render_template( "create_entry.html", vulnerability_details=vulnerability_details, form=form)
def _edit_vuln_internal(vcdb_id: str = None): try: vulnerability_details = VulnerabilityDetails(vcdb_id) vulnerability_view = vulnerability_details.vulnerability_view vulnerability = vulnerability_details.get_or_create_vulnerability() except InvalidIdentifierException as err: return flash_error(str(err), "frontend.serve_index") form = VulnerabilityDetailsForm(obj=vulnerability) # Populate the form data from the vulnerability view if necessary. if form.comment.data == "": form.comment.data = vulnerability_view.comment form_submitted = form.validate_on_submit() if form_submitted and _can_add_proposal(vulnerability): add_proposal(vulnerability, form) return render_template("vulnerability/edit.html", vulnerability_details=vulnerability_details, form=form)
def _edit_vuln_internal(vcdb_id: str = None): try: vulnerability_details = VulnerabilityDetails(vcdb_id) vulnerability_view = vulnerability_details.vulnerability_view vulnerability = vulnerability_details.get_or_create_vulnerability() except InvalidIdentifierException as err: return flash_error(str(err), "frontend.serve_index") form = VulnerabilityDetailsForm(obj=vulnerability) # Populate the form data from the vulnerability view if necessary. if form.comment.data == "": form.comment.data = vulnerability_view.comment form_submitted = form.validate_on_submit() if form_submitted and _can_add_proposal(vulnerability): # TODO: This is incomplete/incorrect as the attached relationships such a GitCommit objects get updated. # We have to ensure everything is properly detached and gets copied before any modifications happen. # Currently, this will incorrectly update relationship objects instead of copying them. form.populate_obj(vulnerability) add_proposal(vulnerability) return render_template("vulnerability/edit.html", vulnerability_details=vulnerability_details, form=form)
def bug_save_editor_data(): try: vulnerability_details = VulnerabilityDetails() vulnerability_details.validate() except InvalidIdentifierException as e: return create_json_response(str(e), 400) vuln_view = vulnerability_details.vulnerability_view if request.method == "POST": if not vuln_view: return create_json_response("Please create an entry first", 404) if not vuln_view.master_commit: current_app.logger.error( f"Vuln (id: {vuln_view.id}) has no linked Git commits!") return create_json_response("Entry has no linked Git link!", 404) master_commit = vulnerability_details.getMasterCommit() # print("DATA: {request.json}" old_files = master_commit.repository_files current_app.logger.debug("%d old files", len(old_files)) # Flush any old custom content of this vulnerability first. new_files = [] for file in request.get_json(): for of in old_files: if of.file_path == file["path"] or of.file_hash == file["hash"]: current_app.logger.debug( "Found old file: %s", (file["path"], file["hash"], file["name"])) file_obj = of break else: current_app.logger.debug( "Creating new file: %s", (file["path"], file["hash"], file["name"])) file_obj = RepositoryFiles( file_name=file["name"], file_path=file["path"], file_patch="DEPRECATED", file_hash=file["hash"], ) # Create comment objects. new_comments = [] for comment in file["comments"]: comment_obj = RepositoryFileComments( row_from=comment["row_from"], row_to=comment["row_to"], text=comment["text"], sort_pos=comment["sort_pos"], creator=g.user, ) new_comments.append(comment_obj) update_file_comments(file_obj, new_comments) # Create marker objects. new_markers = [] for marker in file["markers"]: marker_obj = RepositoryFileMarkers( row_from=marker["row_from"], row_to=marker["row_to"], column_from=marker["column_from"], column_to=marker["column_to"], marker_class=marker["class"], creator=g.user, ) new_markers.append(marker_obj) update_file_markers(file_obj, new_markers) new_files.append(file_obj) current_app.logger.debug("Setting %d files", len(new_files)) master_commit.repository_files = new_files # Update / Insert entries into the database. db.session.commit() return create_json_response("Update successful.") return create_json_response("Accepting only POST requests.", 400)
def __init__(self): self.keyword = None self.top_contributors = [] # TODO: Look into neabling this once public contributions are enabled. # self.fetch_top_contributors() has_annotations_col = Vulnerability.has_annotations vcdb_entries = db.session.query(Vulnerability, Nvd, has_annotations_col) vcdb_entries = vcdb_entries.filter( Vulnerability.state == VulnerabilityState.PUBLISHED) vcdb_entries = vcdb_entries.outerjoin( Nvd, Vulnerability.cve_id == Nvd.cve_id) vcdb_entries = vcdb_entries.options(default_nvd_view_options) vcdb_entries = vcdb_entries.from_self() vcdb_entries = vcdb_entries.order_by( desc(has_annotations_col), asc(Vulnerability.date_created), desc(Vulnerability.id), ) self.vcdb_entries = vcdb_entries nvd_entries = db.session.query(Nvd) nvd_entries = nvd_entries.outerjoin(Vulnerability, Nvd.cve_id == Vulnerability.cve_id) nvd_entries = nvd_entries.options(default_nvd_view_options) nvd_entries = nvd_entries.filter(Vulnerability.cve_id.is_(None)) nvd_entries = nvd_entries.order_by(desc(Nvd.published_date), desc(Nvd.id)) self.nvd_entries = nvd_entries self.keyword = request.args.get("keyword", None, type=str) apply_filter = None if self.keyword: # TODO: Make the filtering work with fulltext search as well. if VulnerabilityDetails.is_cve_id(self.keyword): apply_filter = or_(False, Nvd.cve_id == self.keyword) elif VulnerabilityDetails.is_vcdb_id(self.keyword): apply_filter = or_(False, Vulnerability.id == self.keyword) else: escaped_keyword = self.keyword.replace("%", "") # escaped_keyword = re.sub('[\W]+', ' ', self.keyword) # Attention: We can't use FullText search here because of some # buggy Mysql 5.7 behavior (using FullText on Join results seems # is doing bad things. We might need to apply the filter before # joining below. # apply_filter = or_( # FullTextSearch(escaped_keyword, Nvd, # FullTextMode.BOOLEAN), # FullTextSearch(escaped_keyword, Vulnerability, # FullTextMode.BOOLEAN)) apply_filter = or_( Nvd.descriptions.any( Description.value.like("%" + escaped_keyword + "%")), Vulnerability.comment.like("%" + escaped_keyword + "%"), ) # TODO: add product search support. # apply_filter = or_(apply_filter, Cpe.product == keyword) if apply_filter is not None: self.vcdb_entries = self.vcdb_entries.filter(apply_filter) self.nvd_entries = self.nvd_entries.filter(apply_filter) per_page = 7 vcdb_bookmarked_page = parse_pagination_param("vcdb_p") # Replace a sqlakeyset function to support our use case. # TODO: File a PR for this? sqlakeyset.paging.value_from_thing = custom_value_from_thing self.vcdb_pagination = get_page(self.vcdb_entries, per_page, page=vcdb_bookmarked_page) self.vcdb_pagination = VulnViewTypesetPaginationObjectWrapper( self.vcdb_pagination.paging) num_vuln_entries = db.session.query(func.count( Vulnerability.id)).scalar() self.vcdb_pagination.set_total(num_vuln_entries) nvd_bookmarked_page = parse_pagination_param("nvd_p") self.nvd_pagination = get_page(self.nvd_entries, per_page, page=nvd_bookmarked_page) self.nvd_pagination = VulnViewTypesetPaginationObjectWrapper( self.nvd_pagination.paging) num_nvd_entries = db.session.query(func.count(Nvd.id)).scalar() num_unique_nvd_estimate = num_nvd_entries - num_vuln_entries self.nvd_pagination.set_total(num_unique_nvd_estimate)
def __init__(self): self.keyword = None # TODO: Look into neabling this once public contributions are enabled. # self.top_contributors = [] # self.fetch_top_contributors() vcdb_entries = db.session.query(Vulnerability, Nvd) vcdb_entries = vcdb_entries.outerjoin( Nvd, Vulnerability.cve_id == Nvd.cve_id) vcdb_entries = vcdb_entries.options(default_nvd_view_options) vcdb_entries = vcdb_entries.order_by( asc(Vulnerability.date_created), desc(Vulnerability.id)) self.vcdb_entries = vcdb_entries nvd_entries = db.session.query(Nvd) nvd_entries = nvd_entries.outerjoin(Vulnerability, Nvd.cve_id == Vulnerability.cve_id) nvd_entries = nvd_entries.options(default_nvd_view_options) nvd_entries = nvd_entries.filter(Vulnerability.cve_id.is_(None)) nvd_entries = nvd_entries.order_by( desc(Nvd.published_date), desc(Nvd.id)) self.nvd_entries = nvd_entries self.keyword = request.args.get("keyword", None, type=str) apply_filter = None if self.keyword: # TODO: Make the filtering work with fulltext search as well. if VulnerabilityDetails.is_cve_id(self.keyword): apply_filter = or_(False, Nvd.cve_id == self.keyword) elif VulnerabilityDetails.is_vcdb_id(self.keyword): apply_filter = or_(False, Vulnerability.id == self.keyword) else: escaped_keyword = self.keyword.replace("%", "") # escaped_keyword = re.sub('[\W]+', ' ', self.keyword) # Attention: We can't use FullText search here because of some buggy # Mysql 5.7 behavior (using FullText on Join results seems is doing bad # things. We might need to apply the filter before joining below. # apply_filter = or_( # FullTextSearch(escaped_keyword, Nvd, FullTextMode.BOOLEAN), # FullTextSearch(escaped_keyword, Vulnerability, FullTextMode.BOOLEAN)) apply_filter = or_( Nvd.descriptions.any( Description.value.like("%" + escaped_keyword + "%")), Vulnerability.comment.like("%" + escaped_keyword + "%"), ) # TODO: add product search support. # apply_filter = or_(apply_filter, Cpe.product == keyword) if apply_filter is not None: self.vcdb_entries = self.vcdb_entries.filter(apply_filter) self.nvd_entries = self.nvd_entries.filter(apply_filter) per_page = 7 vcdb_page = request.args.get("vcdb_p", 1, type=int) self.vcdb_pagination = self.vcdb_entries.paginate( vcdb_page, per_page=per_page) self.vcdb_pagination = VulnViewSqlalchemyPaginationObjectWrapper( self.vcdb_pagination) def filter_pagination_param(param): filtered = re.sub('[^a-zA-Z\d\- <>:~]', '', param) return filtered nvd_bookmarked_page = request.args.get('nvd_p', None) if nvd_bookmarked_page: nvd_bookmarked_page = filter_pagination_param(nvd_bookmarked_page) nvd_bookmarked_page = unserialize_bookmark(nvd_bookmarked_page) self.nvd_pagination = get_page( self.nvd_entries, per_page, page=nvd_bookmarked_page) self.nvd_pagination = VulnViewTypesetPaginationObjectWrapper( self.nvd_pagination.paging) num_nvd_entries = db.session.query(Nvd).count() num_vuln_entries = db.session.query(Vulnerability).count() num_unique_nvd_estimate = num_nvd_entries - num_vuln_entries self.nvd_pagination.set_total(num_unique_nvd_estimate)