Skip to content

Commit

Permalink
chg: [website] The dump command can now dump the sightings. It is as …
Browse files Browse the repository at this point in the history
…well possible to execute the dump of the sightings from the Web admin interface.
  • Loading branch information
cedricbonhomme committed Oct 18, 2024
1 parent 946eaaf commit d070c58
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 31 deletions.
91 changes: 68 additions & 23 deletions bin/dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,50 @@
from vulnerabilitylookup.default import get_config, get_homedir, safe_create_dir
from website.models import Bundle
from website.models import Comment
from website.models import Sighting
from website.web.bootstrap import application

logging.config.dictConfig(get_config('logging'))
logging.config.dictConfig(get_config("logging"))

dumps_dir = 'dumps'
excluded_sources = ['cisa_known_exploited']
dumps_dir = "dumps"
excluded_sources = ["cisa_known_exploited"]

class Dump():

class Dump:
def __init__(self) -> None:
self.vl = VulnerabilityLookup()
self.root_dumps = get_homedir() / dumps_dir
safe_create_dir(self.root_dumps)

def dump(self, feed: str, /) -> None:
dest_file = self.root_dumps / f'{feed}.ndjson'
dest_file = self.root_dumps / f"{feed}.ndjson"
dest_file.unlink(missing_ok=True)
for vuln in self.vl.get_all(feed, with_meta=True):
with dest_file.open('a') as f:
with dest_file.open("a") as f:
json.dump(vuln, f)

def dump_comments(self) -> None:
dest_file = self.root_dumps / 'comments.ndjson'
dest_file = self.root_dumps / "comments.ndjson"
dest_file.unlink(missing_ok=True)
with application.app_context():
for comment in Comment.query.filter():
with dest_file.open('a') as f:
with dest_file.open("a") as f:
json.dump(comment.to_dict(), f)

def dump_bundles(self) -> None:
dest_file = self.root_dumps / 'bundles.ndjson'
dest_file = self.root_dumps / "bundles.ndjson"
dest_file.unlink(missing_ok=True)
with application.app_context():
for bundle in Bundle.query.filter():
with dest_file.open('a') as f:
with dest_file.open("a") as f:
json.dump(bundle.to_dict(), f)

def dump_sightings(self) -> None:
dest_file = self.root_dumps / "sightings.ndjson"
dest_file.unlink(missing_ok=True)
with application.app_context():
for bundle in Sighting.query.filter():
with dest_file.open("a") as f:
json.dump(bundle.to_dict(), f)


Expand All @@ -56,49 +65,85 @@ def main() -> None:
description="Dump vulnerability-lookup storage in NDJSON."
)
parser.add_argument(
"--feed", help="Feed to dump. Default is set to nvd.", default="nvd"
"--feed",
help="Feed to dump.",
default="",
choices=[
"nvd",
"cvelistv5",
"pysec",
"github",
"gsd",
"ossf_malicious_packages",
"csaf_certbund",
"csaf_siemens",
"csaf_redhat",
"csaf_cisa",
"csaf_cisco",
"csaf_sick",
"csaf_nozominetworks",
"csaf_ox",
"variot",
"jvndb",
"tailscale",
],
)
parser.add_argument(
"--all", help="Dump all feeds. Default is false", default=False, action="store_true"
"--all",
help="Dump all feeds. Default is false",
default=False,
action="store_true",
)
parser.add_argument(
"--index", help="Generate an index to publish all the feeds. Default is false.", default=False, action="store_true"
"--index",
help="Generate an index to publish all the feeds. Default is false.",
default=False,
action="store_true",
)
parser.add_argument(
"--comments", help="Export the comments. Default is false.", action="store_true"
)
parser.add_argument(
"--bundles", help="Export the bundles. Default is false.", action="store_true"
)
parser.add_argument(
"--sightings",
help="Export the sightings. Default is false.",
action="store_true",
)
args = parser.parse_args()
d = Dump()
if args.index:
index = '<html><meta><title>vulnerability-lookup JSON dumps</title></meta><body><ul>'
if not args.all:
index = "<html><meta><title>vulnerability-lookup JSON dumps</title></meta><body><ul>"
if not args.all and args.feed:
d.dump(args.feed)
else:
elif args.all:
vl = VulnerabilityLookup()
for source in sorted(vl.get_sources()):
if source in excluded_sources:
continue
print(f'Dumping {source} in {dumps_dir}...')
print(f"Dumping {source} in {dumps_dir}...")
if args.index:
index = index + f'\n<li><a href="./{source}.ndjson">{source}</a></li>'
d.dump(source)
if args.index and args.all:
current_date = datetime.now()
root_dumps = get_homedir() / dumps_dir
dest_file = root_dumps / f'index.html'
dest_file = root_dumps / f"index.html"
dest_file.unlink(missing_ok=True)
index = index + f'</ul><br/>Generated on {current_date}</body></html>'
with dest_file.open('w') as f:
index = index + f"</ul><br/>Generated on {current_date}</body></html>"
with dest_file.open("w") as f:
f.write(index)
if args.comments:
print('Dumping comments...')
print("Dumping comments...")
d.dump_comments()
if args.bundles:
print('Dumping bundles...')
print("Dumping bundles...")
d.dump_bundles()
if args.sightings:
print("Dumping sightings...")
d.dump_sightings()


if __name__ == '__main__':
if __name__ == "__main__":
main()
8 changes: 8 additions & 0 deletions website/web/templates/admin/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ <h2 id="instance-status">Maintenance</h2>
<button id="maintenance-warning-lists" class="btn btn-primary" type="button" title="Update the MISP Warning lists in background.">Update MISP Warning lists</button>
<button id="maintenance-backup-database" class="btn btn-primary" type="button" title="Backup the database in background.">Backup database</button>
<button id="maintenance-dump-feeds" class="btn btn-primary" type="button" title="Dump all feeds in background.">Dump all feeds</button>
<button id="maintenance-dump-sightings" class="btn btn-primary" type="button" title="Dump all sightings in background.">Dump sightings</button>
</div>
</div>
<br />
Expand Down Expand Up @@ -82,6 +83,13 @@ <h2 id="active-users">Active users</h2>
rpc_maintainance("/admin/command/dump_feeds");
}
})

document.getElementById("maintenance-dump-sightings").addEventListener('click',function (event)
{
if (confirm("Dump all sightings in background ?") == true) {
rpc_maintainance("/admin/command/dump_sightings");
}
})
});

function rpc_maintainance(url) {
Expand Down
20 changes: 12 additions & 8 deletions website/web/templates/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@
<style>
.top-right-card {
max-width: 500px;
min-height: 100px;
padding-bottom: 40px;
}

.small-list-group-item {
padding: 5px 10px; /* Adjust the padding to reduce height */
}

/* Style to make the chart scrollable horizontally */
.chart-container {
position: relative; /* Required for positioning */
Expand All @@ -33,14 +38,16 @@
<div class="d-flex flex-column">

{% if not vulnerability_id and not vendor %}
<!-- Main content area with adjusted margin for navbar -->
<div class="container-fluid d-none d-xl-block">
<div class="container-fluid">
<!-- Top Right Card Aligned in Parent Container -->
<div class="d-flex justify-content-end">
<div class="top-right-card">
<div id="commentsContainer" class="card">
<div id="commentsContainer" class="card d-none d-xl-block">
<div class="card-body">
<ul id="list-comments" class="list-group list-group-flush"></ul>
<ul id="list-comments" class="list-group list-group-flush"></ul>
</div>
<div class="card-footer text-end text-muted">
{{ render_icon('rss', color='yellow') }}
</div>
</div>
</div>
Expand All @@ -49,7 +56,6 @@
{% endif %}

<div class="container flex-grow-1 d-flex flex-column justify-content-center">
<!-- Centered Form -->
<div class="row justify-content-center">
<div class="col-md-4">
<form class="row pb-5 g-3" role="form" method="post" action="/search" enctype="multipart/form-data">
Expand All @@ -68,9 +74,7 @@
</div>

{% if not vulnerability_id and not vendor %}
<!-- Bottom Section with 3 Columns (just above the footer) -->
<div class="container-fluid pt-5 d-none d-xl-block">
<br /><br /><br />
<div class="row justify-content-between">
<div class="col text-start">
<div id="sightingsChartContainerExploited" class="chart-container">
Expand Down Expand Up @@ -336,7 +340,7 @@ <h5>All the vulnerabilites related to {{vendor}} - {{product}}</h5>
})
.map(function (comment) {
var element = document.createElement("li");
element.setAttribute("class", "list-group-item");
element.setAttribute("class", "list-group-item small-list-group-item");
element.innerHTML = '<a href="/user/'+comment.author.login+'">' + comment.author.login +
'</a> commented on <a href="/comment/'+comment.uuid+'">'+comment.vulnerability+'</a>';
document.getElementById("list-comments").appendChild(element);
Expand Down
8 changes: 8 additions & 0 deletions website/web/views/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ def dump_feeds() -> WerkzeugResponse:
return jsonify({"message": "Command executed."})


@admin_bp.route("/command/dump_sightings", methods=["GET"])
@login_required # type: ignore[misc]
@admin_permission.require(http_exception=403) # type: ignore[misc]
def dump_sightings() -> WerkzeugResponse:
exec_cmd_no_wait("poetry run dump --sightings")
return jsonify({"message": "Command executed."})


#
# Users
#
Expand Down

0 comments on commit d070c58

Please sign in to comment.