diff --git a/integrations/emailrep/manifest.yaml b/integrations/emailrep/manifest.yaml new file mode 100644 index 0000000..f15d25e --- /dev/null +++ b/integrations/emailrep/manifest.yaml @@ -0,0 +1,47 @@ +id: emailrep +name: EmailRep +version: 1.0.0 +description: "EmailRep.io (API) — reputation and risk profile of an email address (deliverability, first/last seen, malicious activity, breaches, profiles), plus reporting an address as malicious. API-key authentication; stdlib-only, no extra Python dependencies." +changelog: "1.0.0 — Initial release: email reputation lookup and malicious-address reporting." +category: enrichment + +config_schema: + properties: + api_key: + type: string + description: "EmailRep.io API key" + x-soar-sensitive: true + required: + - api_key + +commands: + - id: get_reputation + name: emailrep-get-reputation + description: "Get the reputation and risk profile of an email address." + risk: read + inputs_schema: + properties: + email: { type: string, description: "Email address" } + required: [email] + outputs_schema: { properties: {} } + - id: report + name: emailrep-report + description: "Report an email address as malicious to EmailRep.io." + inputs_schema: + properties: + email: { type: string, description: "Email address to report" } + tags: { type: string, description: "Comma-separated tags, e.g. bec,phishing (see EmailRep docs for the allowed set)" } + description: { type: string, description: "Free-text description of the malicious activity" } + timestamp: { type: number, description: "Unix time the activity occurred (default now)" } + expires: { type: number, description: "Days after which the report expires" } + required: [email, tags] + outputs_schema: { properties: {} } + + - id: test_connection + name: emailrep-test-connection + description: "Verify the API key (used by the Test button)." + risk: read + inputs_schema: + properties: {} + required: [] + outputs_schema: { properties: {} } diff --git a/integrations/emailrep/scripts/get_reputation.py b/integrations/emailrep/scripts/get_reputation.py new file mode 100644 index 0000000..e945cb4 --- /dev/null +++ b/integrations/emailrep/scripts/get_reputation.py @@ -0,0 +1,42 @@ +import json, os, sys, urllib.parse, urllib.request, urllib.error + +API = "https://emailrep.io" + + +def _cfg(): + return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}")) + + +def request(method, path, body=None): + url = API + path + data = json.dumps(body).encode("utf-8") if body is not None else None + headers = {"Accept": "application/json", "Key": str(_cfg().get("api_key") or ""), + "User-Agent": "Riposte"} + if data is not None: + headers["Content-Type"] = "application/json" + req = urllib.request.Request(url, data=data, headers=headers, method=method) + with urllib.request.urlopen(req, timeout=60) as r: + raw = r.read() + return json.loads(raw) if raw else {} + + +q = lambda v: urllib.parse.quote(str(v), safe="") + + +def main(): + inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}")) + email = inputs.get("email") + if not email: + raise Exception("email is required") + res = request("GET", "/" + q(email)) + print(json.dumps(res)) + + +try: + main() +except urllib.error.HTTPError as e: + print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")})) + sys.exit(1) +except Exception as e: + print(json.dumps({"error": str(e)})) + sys.exit(1) diff --git a/integrations/emailrep/scripts/report.py b/integrations/emailrep/scripts/report.py new file mode 100644 index 0000000..0eec9c1 --- /dev/null +++ b/integrations/emailrep/scripts/report.py @@ -0,0 +1,55 @@ +import json, os, sys, urllib.parse, urllib.request, urllib.error + +API = "https://emailrep.io" + + +def _cfg(): + return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}")) + + +def request(method, path, body=None): + url = API + path + data = json.dumps(body).encode("utf-8") if body is not None else None + headers = {"Accept": "application/json", "Key": str(_cfg().get("api_key") or ""), + "User-Agent": "Riposte"} + if data is not None: + headers["Content-Type"] = "application/json" + req = urllib.request.Request(url, data=data, headers=headers, method=method) + with urllib.request.urlopen(req, timeout=60) as r: + raw = r.read() + return json.loads(raw) if raw else {} + + +q = lambda v: urllib.parse.quote(str(v), safe="") + + +def main(): + inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}")) + email = inputs.get("email") + if not email: + raise Exception("email is required") + tags = inputs.get("tags") + if not tags: + raise Exception("tags is required") + body = {"email": email, "tags": [t.strip() for t in tags.split(",") if t.strip()]} + description = inputs.get("description") + if description: + body["description"] = description + timestamp = inputs.get("timestamp") + if timestamp: + body["timestamp"] = int(timestamp) + expires = inputs.get("expires") + if expires: + body["expires"] = int(expires) + res = request("POST", "/report", body=body) + print(json.dumps(res)) + + +try: + main() +except urllib.error.HTTPError as e: + print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")})) + sys.exit(1) +except Exception as e: + print(json.dumps({"error": str(e)})) + sys.exit(1) diff --git a/integrations/emailrep/scripts/test_connection.py b/integrations/emailrep/scripts/test_connection.py new file mode 100644 index 0000000..b0ae16c --- /dev/null +++ b/integrations/emailrep/scripts/test_connection.py @@ -0,0 +1,40 @@ +import json, os, sys, urllib.parse, urllib.request, urllib.error + +API = "https://emailrep.io" + + +def _cfg(): + return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}")) + + +def request(method, path, body=None): + url = API + path + data = json.dumps(body).encode("utf-8") if body is not None else None + headers = {"Accept": "application/json", "Key": str(_cfg().get("api_key") or ""), + "User-Agent": "Riposte"} + if data is not None: + headers["Content-Type"] = "application/json" + req = urllib.request.Request(url, data=data, headers=headers, method=method) + with urllib.request.urlopen(req, timeout=60) as r: + raw = r.read() + return json.loads(raw) if raw else {} + + +q = lambda v: urllib.parse.quote(str(v), safe="") + + +def main(): + res = request("GET", "/test@example.com") + if not isinstance(res, dict) or "email" not in res: + raise Exception("unexpected response") + print(json.dumps({"ok": True})) + + +try: + main() +except urllib.error.HTTPError as e: + print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")})) + sys.exit(1) +except Exception as e: + print(json.dumps({"error": str(e)})) + sys.exit(1)