Skip to content

Commit 67c60fc

Browse files
chg: [core] Using the --sighting argument, detected vulnerability IDs will be recorded in Vulnerability Lookup as sightings.
1 parent 6aeb31d commit 67c60fc

File tree

6 files changed

+77
-20
lines changed

6 files changed

+77
-20
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ You only have to execute it once.
4040

4141
```bash
4242
$ poetry shell
43-
$ FediVuln-Stream --user
43+
$ FediVuln-Stream --user --sighting
4444
```
4545

46+
Using the ``--sighting`` argument, detected vulnerability IDs will be recorded in Vulnerability Lookup as sightings.
47+
4648

4749
### Publishing
4850

fedivuln/publish.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import argparse
22

3-
from mastodon import Mastodon # type: ignore[import-untyped]
3+
from mastodon import Mastodon
44

55
from fedivuln import config
66

fedivuln/register.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from mastodon import Mastodon # type: ignore[import-untyped]
1+
from mastodon import Mastodon
22

33
from fedivuln import config
44

fedivuln/stream.py

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import argparse
22
import re
33
import sys
4+
import urllib.parse
45

5-
from mastodon import Mastodon, StreamListener # type: ignore[import-untyped]
6+
import requests
7+
from mastodon import Mastodon, StreamListener
68

79
from fedivuln import config
810

@@ -15,24 +17,33 @@
1517

1618
# Listener class for handling stream events
1719
class VulnStreamListener(StreamListener):
18-
# Regular expression to match CVE, GHSA, and PySec IDs
19-
cve_pattern = re.compile(r"\bCVE-\d{4}-\d{4,}\b", re.IGNORECASE)
20-
ghsa_pattern = re.compile(
21-
r"GHSA-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}", re.IGNORECASE
22-
)
23-
pysec_pattern = re.compile(r"PYSEC-\d{4}-\d{2,5}", re.IGNORECASE)
20+
def __init__(self, sighting: bool = False):
21+
# Regular expression to match CVE, GHSA, and PySec IDs
22+
self.vulnerability_pattern = re.compile(
23+
r"\b(CVE-\d{4}-\d{4,})\b" # CVE pattern
24+
r"|\b(GHSA-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4})\b" # GHSA pattern
25+
r"|\b(PYSEC-\d{4}-\d{2,5})\b", # PYSEC pattern
26+
re.IGNORECASE,
27+
)
28+
self.sighting = sighting
2429

2530
# When a new status (post) is received
2631
def on_update(self, status):
2732
print("New status received.")
2833
content = status["content"]
29-
if (
30-
self.cve_pattern.search(content)
31-
or self.ghsa_pattern.search(content)
32-
or self.pysec_pattern.search(content)
33-
):
34-
print("Vulnerability detected:")
35-
print(status) # Prints the full HTML content of the status
34+
vulnerability_ids = self.vulnerability_pattern.findall(
35+
content
36+
) # Find all matches in the content
37+
# Filter out empty matches and print any found IDs
38+
vulnerability_ids = [match for match in vulnerability_ids if match]
39+
if vulnerability_ids:
40+
print("Vulnerability IDs detected:")
41+
print("Vulnerability IDs found:", ", ".join(vulnerability_ids))
42+
print(status) # Prints the full status
43+
if self.sighting:
44+
push_to_vulnerability_lookup(
45+
vulnerability_ids
46+
) # Push a sighting to Vulnerability Lookup
3647
else:
3748
print("Ignoring.")
3849

@@ -51,8 +62,29 @@ def on_abort(self, err):
5162
print("Stream aborted with error:", err)
5263

5364

54-
# Instantiate the listener
55-
listener = VulnStreamListener()
65+
def push_to_vulnerability_lookup(vulnerability_ids):
66+
"""Create a sighting from an incoming status and push it to the Vulnerability Lookup instance."""
67+
print("Pushing sighting to Vulnerability Lookup...")
68+
headers_json = {
69+
"Content-Type": "application/json",
70+
"accept": "application/json",
71+
}
72+
sighting = {"type": "seen", "vulnerability": vulnerability_ids[0]}
73+
try:
74+
r = requests.post(
75+
urllib.parse.urljoin(config.vulnerability_lookup_base_url, "sighting/"),
76+
json=sighting,
77+
headers=headers_json,
78+
auth=("admin", "token"),
79+
)
80+
if r.status_code not in (200, 201):
81+
print(
82+
f"Error when sending POST request to the Vulnerability Lookup server: {r.reason}"
83+
)
84+
except requests.exceptions.ConnectionError as e:
85+
print(
86+
f"Error when sending POST request to the Vulnerability Lookup server:\n{e}"
87+
)
5688

5789

5890
def main():
@@ -67,9 +99,17 @@ def main():
6799
action="store_true",
68100
help="Streams public events.",
69101
)
102+
parser.add_argument(
103+
"--sighting",
104+
action="store_true",
105+
help="Push the sightings to Vulnerability Lookup.",
106+
)
70107

71108
arguments = parser.parse_args()
72109

110+
# Instantiate the listener
111+
listener = VulnStreamListener(sighting=arguments.sighting)
112+
73113
if arguments.user:
74114
print("Starting user stream...")
75115
mastodon.stream_user(listener)

poetry.lock

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ mastodon-py = "^1.8.1"
4141
mypy = "^1.13.0"
4242
flake8 = "^6.0.0"
4343
pre-commit = "^4.0.1"
44+
types-requests = "^2.32.0.20241016"
4445

4546

4647
[build-system]

0 commit comments

Comments
 (0)