feat(cortex-xdr): new Cortex XDR integration — incident ingestion + OCSF mapper, IR actions, standard/advanced auth
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
id: cortex_xdr
|
||||
name: Cortex XDR
|
||||
version: 1.0.0
|
||||
description: "Palo Alto Cortex XDR (public API v1) — incident ingestion, endpoint isolation, RTR scripts, hash block/allow lists, file quarantine/restore, scans and alert retrieval."
|
||||
changelog: "1.0.0 — Initial release: incident ingestion (get_incidents) with OCSF mapper, endpoints, isolate/unisolate, scan, hash blocklist/allowlist, quarantine/restore, run script + results, alerts retrieval, distributions and action status. Standard or Advanced API authentication."
|
||||
category: endpoint
|
||||
|
||||
# Per-instance configuration. The base URL is the tenant API root, e.g.
|
||||
# https://api-yourtenant.xdr.eu.paloaltonetworks.com (scripts append /public_api/v1).
|
||||
config_schema:
|
||||
properties:
|
||||
url:
|
||||
type: string
|
||||
description: "Cortex XDR API base URL, e.g. https://api-<tenant>.xdr.<region>.paloaltonetworks.com"
|
||||
api_key_id:
|
||||
type: string
|
||||
description: "API Key ID (the integer ID shown next to the API key in Settings → API Keys)"
|
||||
api_key:
|
||||
type: string
|
||||
description: "API Key secret"
|
||||
x-soar-sensitive: true
|
||||
auth_type:
|
||||
type: string
|
||||
description: "Authentication method: standard (key sent as-is) or advanced (nonce + timestamp SHA-256 hash)"
|
||||
default: standard
|
||||
required:
|
||||
- url
|
||||
- api_key_id
|
||||
- api_key
|
||||
|
||||
# Documented for reference; the bundled scripts build the headers themselves.
|
||||
# Standard: x-xdr-auth-id: <id>, Authorization: <api_key>
|
||||
# Advanced: x-xdr-auth-id: <id>, x-xdr-nonce, x-xdr-timestamp,
|
||||
# Authorization: sha256(api_key + nonce + timestamp)
|
||||
auth:
|
||||
- id: apikey
|
||||
type: api_key
|
||||
in: header
|
||||
name: Authorization
|
||||
value_template: "{{secret}}"
|
||||
secret_field: api_key
|
||||
|
||||
commands:
|
||||
# ── Ingestion ─────────────────────────────────────────────────────────────
|
||||
- id: get_incidents
|
||||
name: cortex-xdr-get-incidents
|
||||
description: "Fetch Cortex XDR incidents for ingestion. Returns {reply:{incidents:[...]}}; use reply.incidents as the alert rule results path."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
status: { type: string, description: "Filter by status (e.g. new, under_investigation, resolved_threat_handled)" }
|
||||
created_after: { type: string, description: "Lower bound on creation_time, ISO8601 or epoch ms (incremental fetch watermark)" }
|
||||
limit: { type: number, description: "Maximum incidents to fetch (default 100)" }
|
||||
required: []
|
||||
outputs_schema: { properties: {} }
|
||||
ingest:
|
||||
results_path: reply.incidents
|
||||
dedup_key: incident_id
|
||||
incremental_field: created_after
|
||||
- id: get_incident_extra_data
|
||||
name: cortex-xdr-get-incident-extra-data
|
||||
description: "Get full incident data including its alerts and network artifacts by incident ID."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
incident_id: { type: string, description: "Incident ID" }
|
||||
alerts_limit: { type: number, description: "Max alerts to return (default 1000)" }
|
||||
required: [incident_id]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: get_alerts
|
||||
name: cortex-xdr-get-alerts
|
||||
description: "Retrieve alerts using a custom filter (get_alerts_by_filter_data). Returns rich alert objects."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
severity: { type: string, description: "Comma-separated severities (low, medium, high, critical)" }
|
||||
created_after: { type: string, description: "Lower bound on alert source_insert_ts, epoch ms" }
|
||||
limit: { type: number, description: "Maximum alerts to fetch (default 100)" }
|
||||
required: []
|
||||
outputs_schema: { properties: {} }
|
||||
|
||||
# ── Endpoints ─────────────────────────────────────────────────────────────
|
||||
- id: get_endpoints
|
||||
name: cortex-xdr-get-endpoints
|
||||
description: "List/search endpoints by hostname, IP, status, platform, group, etc."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
hostname: { type: string, description: "Hostname to filter by" }
|
||||
ip_list: { type: string, description: "Comma-separated IPs" }
|
||||
status: { type: string, description: "Endpoint status (connected, disconnected, ...)" }
|
||||
platform: { type: string, description: "OS platform (windows, linux, macos, android)" }
|
||||
limit: { type: number, description: "Max endpoints (default 30)" }
|
||||
required: []
|
||||
outputs_schema: { properties: {} }
|
||||
- id: isolate_endpoint
|
||||
name: cortex-xdr-isolate-endpoint
|
||||
description: "Network-isolate an endpoint by endpoint (agent) ID."
|
||||
inputs_schema:
|
||||
properties:
|
||||
endpoint_id: { type: string, description: "Endpoint (agent) ID to isolate" }
|
||||
incident_id: { type: string, description: "Optional incident ID to associate the action with" }
|
||||
required: [endpoint_id]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: unisolate_endpoint
|
||||
name: cortex-xdr-unisolate-endpoint
|
||||
description: "Remove network isolation from an endpoint by endpoint (agent) ID."
|
||||
inputs_schema:
|
||||
properties:
|
||||
endpoint_id: { type: string, description: "Endpoint (agent) ID to unisolate" }
|
||||
incident_id: { type: string, description: "Optional incident ID to associate the action with" }
|
||||
required: [endpoint_id]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: scan_endpoints
|
||||
name: cortex-xdr-scan-endpoints
|
||||
description: "Trigger a malware scan on endpoints matching the given filters (or all)."
|
||||
inputs_schema:
|
||||
properties:
|
||||
endpoint_id_list: { type: string, description: "Comma-separated endpoint IDs (omit + use all=true to scan all)" }
|
||||
hostname: { type: string, description: "Comma-separated hostnames" }
|
||||
all: { type: boolean, description: "Scan all endpoints when true and no other filter is set" }
|
||||
incident_id: { type: string, description: "Optional incident ID" }
|
||||
required: []
|
||||
outputs_schema: { properties: {} }
|
||||
- id: get_policy
|
||||
name: cortex-xdr-get-policy
|
||||
description: "Get the policy name applied to an endpoint."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
endpoint_id: { type: string, description: "Endpoint (agent) ID" }
|
||||
required: [endpoint_id]
|
||||
outputs_schema: { properties: {} }
|
||||
|
||||
# ── Hash block / allow lists ──────────────────────────────────────────────
|
||||
- id: blocklist_files
|
||||
name: cortex-xdr-blocklist-files
|
||||
description: "Add file hashes to the block list."
|
||||
inputs_schema:
|
||||
properties:
|
||||
hash_list: { type: string, description: "Comma-separated SHA-256 hashes to block" }
|
||||
comment: { type: string, description: "Optional comment" }
|
||||
incident_id: { type: string, description: "Optional incident ID" }
|
||||
required: [hash_list]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: remove_blocklist_files
|
||||
name: cortex-xdr-remove-blocklist-files
|
||||
description: "Remove file hashes from the block list."
|
||||
inputs_schema:
|
||||
properties:
|
||||
hash_list: { type: string, description: "Comma-separated SHA-256 hashes to remove" }
|
||||
comment: { type: string, description: "Optional comment" }
|
||||
incident_id: { type: string, description: "Optional incident ID" }
|
||||
required: [hash_list]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: allowlist_files
|
||||
name: cortex-xdr-allowlist-files
|
||||
description: "Add file hashes to the allow list."
|
||||
inputs_schema:
|
||||
properties:
|
||||
hash_list: { type: string, description: "Comma-separated SHA-256 hashes to allow" }
|
||||
comment: { type: string, description: "Optional comment" }
|
||||
incident_id: { type: string, description: "Optional incident ID" }
|
||||
required: [hash_list]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: remove_allowlist_files
|
||||
name: cortex-xdr-remove-allowlist-files
|
||||
description: "Remove file hashes from the allow list."
|
||||
inputs_schema:
|
||||
properties:
|
||||
hash_list: { type: string, description: "Comma-separated SHA-256 hashes to remove" }
|
||||
comment: { type: string, description: "Optional comment" }
|
||||
incident_id: { type: string, description: "Optional incident ID" }
|
||||
required: [hash_list]
|
||||
outputs_schema: { properties: {} }
|
||||
|
||||
# ── File quarantine / restore ─────────────────────────────────────────────
|
||||
- id: quarantine_files
|
||||
name: cortex-xdr-quarantine-files
|
||||
description: "Quarantine a file by path + hash on the given endpoints."
|
||||
inputs_schema:
|
||||
properties:
|
||||
endpoint_id_list: { type: string, description: "Comma-separated endpoint IDs" }
|
||||
file_path: { type: string, description: "Full path of the file to quarantine" }
|
||||
file_hash: { type: string, description: "SHA-256 of the file" }
|
||||
incident_id: { type: string, description: "Optional incident ID" }
|
||||
required: [endpoint_id_list, file_path, file_hash]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: restore_file
|
||||
name: cortex-xdr-restore-file
|
||||
description: "Restore a quarantined file by hash."
|
||||
inputs_schema:
|
||||
properties:
|
||||
file_hash: { type: string, description: "SHA-256 of the file to restore" }
|
||||
endpoint_id: { type: string, description: "Optional endpoint ID" }
|
||||
incident_id: { type: string, description: "Optional incident ID" }
|
||||
required: [file_hash]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: get_quarantine_status
|
||||
name: cortex-xdr-get-quarantine-status
|
||||
description: "Check whether a file is quarantined on an endpoint."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
endpoint_id: { type: string, description: "Endpoint ID" }
|
||||
file_path: { type: string, description: "File path" }
|
||||
file_hash: { type: string, description: "SHA-256 of the file" }
|
||||
required: [endpoint_id, file_path, file_hash]
|
||||
outputs_schema: { properties: {} }
|
||||
|
||||
# ── Real-time scripts ─────────────────────────────────────────────────────
|
||||
- id: run_script
|
||||
name: cortex-xdr-run-script
|
||||
description: "Run a script (by UID) on endpoints with optional parameters."
|
||||
inputs_schema:
|
||||
properties:
|
||||
script_uid: { type: string, description: "Script UID" }
|
||||
endpoint_ids: { type: string, description: "Comma-separated endpoint IDs" }
|
||||
parameters: { type: string, description: "JSON object of parameter values" }
|
||||
timeout: { type: number, description: "Timeout in seconds (default 600)" }
|
||||
incident_id: { type: string, description: "Optional incident ID" }
|
||||
required: [script_uid, endpoint_ids]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: get_script_execution_results
|
||||
name: cortex-xdr-get-script-execution-results
|
||||
description: "Get the results of a script execution by action ID."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
action_id: { type: string, description: "Action ID returned by run_script" }
|
||||
required: [action_id]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: get_scripts
|
||||
name: cortex-xdr-get-scripts
|
||||
description: "List available scripts, optionally filtered by name/description/OS support."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
name: { type: string, description: "Comma-separated script names" }
|
||||
windows_supported: { type: boolean, description: "Filter scripts supporting Windows" }
|
||||
required: []
|
||||
outputs_schema: { properties: {} }
|
||||
|
||||
# ── Actions / misc ────────────────────────────────────────────────────────
|
||||
- id: action_status
|
||||
name: cortex-xdr-action-status
|
||||
description: "Get the status of a group action by action ID."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
action_id: { type: string, description: "Group action ID" }
|
||||
required: [action_id]
|
||||
outputs_schema: { properties: {} }
|
||||
- id: get_distribution_versions
|
||||
name: cortex-xdr-get-distribution-versions
|
||||
description: "List available agent installer versions."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties: {}
|
||||
required: []
|
||||
outputs_schema: { properties: {} }
|
||||
|
||||
- id: test_connection
|
||||
name: cortex-xdr-test-connection
|
||||
description: "Verify connectivity and credentials (used by the Test button)."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties: {}
|
||||
required: []
|
||||
outputs_schema: { properties: {} }
|
||||
@@ -0,0 +1,24 @@
|
||||
name: "Cortex XDR Incidents → OCSF"
|
||||
description: "Maps a Cortex XDR incident (incidents/get_incidents/, results_path = reply.incidents) to OCSF finding fields. Incidents are aggregates; use get_incident_extra_data for per-alert detail."
|
||||
field_mappings:
|
||||
title: "incident_name"
|
||||
severity: "severity = 'critical' ? 5 : (severity = 'high' ? 4 : (severity = 'medium' ? 3 : 2))"
|
||||
description: "description"
|
||||
# results_path = reply.incidents; source_path is JSONata over ONE incident object.
|
||||
# Paths absent from a given incident are skipped at ingestion, so extra entries are safe.
|
||||
ocsf:
|
||||
# ── Finding ───────────────────────────────────────────────────────
|
||||
- { source_path: "incident_id", ocsf_field: "finding_info.uid" }
|
||||
- { source_path: "incident_name", ocsf_field: "finding_info.title" }
|
||||
- { source_path: "description", ocsf_field: "finding_info.desc" }
|
||||
- { source_path: "creation_time", ocsf_field: "finding_info.created_time" }
|
||||
- { source_path: "modification_time", ocsf_field: "finding_info.modified_time" }
|
||||
- { source_path: "xdr_url", ocsf_field: "finding_info.src_url" }
|
||||
- { source_path: "status", ocsf_field: "status" }
|
||||
- { source_path: "alert_count", ocsf_field: "count" }
|
||||
# ── MITRE ATT&CK (first aggregated tactic/technique) ──────────────
|
||||
- { source_path: "mitre_tactics_ids_and_names[0]", ocsf_field: "attacks.tactic.name" }
|
||||
- { source_path: "mitre_techniques_ids_and_names[0]", ocsf_field: "attacks.technique.name" }
|
||||
# ── Affected host / user (hosts are 'hostname:agent_id' strings) ──
|
||||
- { source_path: "$split(hosts[0], ':')[0]", ocsf_field: "src_endpoint.hostname" }
|
||||
- { source_path: "users[0]", ocsf_field: "user.name" }
|
||||
@@ -0,0 +1,42 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
print(json.dumps(post("/actions/get_action_status/", {"group_action_id": inputs.get("action_id")})))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,51 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {"hash_list": csv(inputs.get("hash_list"))}
|
||||
if inputs.get("comment"):
|
||||
rd["comment"] = inputs["comment"]
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/hash_exceptions/allowlist/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,51 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {"hash_list": csv(inputs.get("hash_list"))}
|
||||
if inputs.get("comment"):
|
||||
rd["comment"] = inputs["comment"]
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/hash_exceptions/blocklist/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,69 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def to_ms(v):
|
||||
if v in (None, ""):
|
||||
return None
|
||||
s = str(v)
|
||||
if s.isdigit():
|
||||
return int(s)
|
||||
try:
|
||||
return int(datetime.fromisoformat(s.replace("Z", "+00:00")).timestamp() * 1000)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
limit = int(inputs.get("limit") or 100)
|
||||
filters = []
|
||||
if inputs.get("severity"):
|
||||
filters.append({"field": "severity", "operator": "in", "value": csv(inputs["severity"])})
|
||||
created_ms = to_ms(inputs.get("created_after"))
|
||||
if created_ms is not None:
|
||||
filters.append({"field": "source_insert_ts", "operator": "gte", "value": created_ms})
|
||||
rd = {"search_from": 0, "search_to": limit, "sort": {"field": "source_insert_ts", "keyword": "desc"}}
|
||||
if filters:
|
||||
rd["filters"] = filters
|
||||
print(json.dumps(post("/alerts/get_alerts_by_filter_data/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,41 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
print(json.dumps(post("/distributions/get_versions/", {})))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,56 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
limit = int(inputs.get("limit") or 30)
|
||||
filters = []
|
||||
if inputs.get("hostname"):
|
||||
filters.append({"field": "hostname", "operator": "in", "value": csv(inputs["hostname"])})
|
||||
if inputs.get("ip_list"):
|
||||
filters.append({"field": "ip_list", "operator": "in", "value": csv(inputs["ip_list"])})
|
||||
if inputs.get("status"):
|
||||
filters.append({"field": "endpoint_status", "operator": "IN", "value": csv(inputs["status"])})
|
||||
if inputs.get("platform"):
|
||||
filters.append({"field": "platform", "operator": "in", "value": csv(inputs["platform"])})
|
||||
print(json.dumps(post("/endpoints/get_endpoint/", {"search_from": 0, "search_to": limit, "filters": filters})))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,43 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {"incident_id": inputs.get("incident_id"), "alerts_limit": int(inputs.get("alerts_limit") or 1000)}
|
||||
print(json.dumps(post("/incidents/get_incident_extra_data/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,69 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def to_ms(v):
|
||||
if v in (None, ""):
|
||||
return None
|
||||
s = str(v)
|
||||
if s.isdigit():
|
||||
return int(s)
|
||||
try:
|
||||
return int(datetime.fromisoformat(s.replace("Z", "+00:00")).timestamp() * 1000)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
limit = int(inputs.get("limit") or 100)
|
||||
filters = []
|
||||
if inputs.get("status"):
|
||||
filters.append({"field": "status", "operator": "eq", "value": inputs["status"]})
|
||||
created_ms = to_ms(inputs.get("created_after"))
|
||||
if created_ms is not None:
|
||||
filters.append({"field": "creation_time", "operator": "gte", "value": created_ms})
|
||||
request_data = {
|
||||
"search_from": 0,
|
||||
"search_to": limit,
|
||||
"sort": {"field": "creation_time", "keyword": "desc"},
|
||||
}
|
||||
if filters:
|
||||
request_data["filters"] = filters
|
||||
print(json.dumps(post("/incidents/get_incidents/", request_data)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,42 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
print(json.dumps(post("/endpoints/get_policy/", {"endpoint_id": inputs.get("endpoint_id")})))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,43 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {"files": [{"endpoint_id": inputs.get("endpoint_id"), "file_path": inputs.get("file_path"), "file_hash": inputs.get("file_hash")}]}
|
||||
print(json.dumps(post("/quarantine/status/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,42 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
print(json.dumps(post("/scripts/get_script_execution_results", {"action_id": inputs.get("action_id")})))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,52 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
filters = []
|
||||
if inputs.get("name"):
|
||||
filters.append({"field": "name", "operator": "in", "value": csv(inputs["name"])})
|
||||
ws = inputs.get("windows_supported")
|
||||
if ws not in (None, ""):
|
||||
filters.append({"field": "windows_supported", "operator": "in", "value": [bool(ws)]})
|
||||
print(json.dumps(post("/scripts/get_scripts/", {"filters": filters})))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,45 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {"endpoint_id": inputs.get("endpoint_id")}
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/endpoints/isolate", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,53 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {
|
||||
"filters": [{"field": "endpoint_id_list", "operator": "in", "value": csv(inputs.get("endpoint_id_list"))}],
|
||||
"file_path": inputs.get("file_path"),
|
||||
"file_hash": inputs.get("file_hash"),
|
||||
}
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/endpoints/quarantine/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,51 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {"hash_list": csv(inputs.get("hash_list"))}
|
||||
if inputs.get("comment"):
|
||||
rd["comment"] = inputs["comment"]
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/hash_exceptions/allowlist/remove/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,51 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {"hash_list": csv(inputs.get("hash_list"))}
|
||||
if inputs.get("comment"):
|
||||
rd["comment"] = inputs["comment"]
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/hash_exceptions/blocklist/remove/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,47 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {"file_hash": inputs.get("file_hash")}
|
||||
if inputs.get("endpoint_id"):
|
||||
rd["endpoint_id"] = inputs["endpoint_id"]
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/endpoints/restore/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,58 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
try:
|
||||
params = json.loads(inputs.get("parameters") or "{}")
|
||||
except Exception:
|
||||
params = {}
|
||||
rd = {
|
||||
"script_uid": inputs.get("script_uid"),
|
||||
"timeout": int(inputs.get("timeout") or 600),
|
||||
"filters": [{"field": "endpoint_id_list", "operator": "in", "value": csv(inputs.get("endpoint_ids"))}],
|
||||
"parameters_values": params,
|
||||
}
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/scripts/run_script/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,54 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def csv(v):
|
||||
return [x.strip() for x in str(v or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
filters = []
|
||||
if inputs.get("endpoint_id_list"):
|
||||
filters.append({"field": "endpoint_id_list", "operator": "in", "value": csv(inputs["endpoint_id_list"])})
|
||||
if inputs.get("hostname"):
|
||||
filters.append({"field": "hostname", "operator": "in", "value": csv(inputs["hostname"])})
|
||||
rd = {"filters": filters if filters else "all"}
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/endpoints/scan/", rd)))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,41 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
print(json.dumps(post("/distributions/get_versions/", {})))
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,45 @@
|
||||
import json, os, sys, time, hashlib, secrets, string, urllib.request, urllib.error
|
||||
|
||||
|
||||
def _client():
|
||||
s = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
base = s.get("url", "").rstrip("/") + "/public_api/v1"
|
||||
key = s.get("api_key", "")
|
||||
kid = str(s.get("api_key_id", ""))
|
||||
headers = {"x-xdr-auth-id": kid, "Content-Type": "application/json", "Accept": "application/json"}
|
||||
if str(s.get("auth_type") or "standard").lower() == "advanced":
|
||||
nonce = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
ts = str(int(time.time()) * 1000)
|
||||
headers["x-xdr-nonce"] = nonce
|
||||
headers["x-xdr-timestamp"] = ts
|
||||
headers["Authorization"] = hashlib.sha256((key + nonce + ts).encode("utf-8")).hexdigest()
|
||||
else:
|
||||
headers["Authorization"] = key
|
||||
return base, headers
|
||||
|
||||
|
||||
def post(path, request_data):
|
||||
base, headers = _client()
|
||||
data = json.dumps({"request_data": request_data}).encode("utf-8")
|
||||
req = urllib.request.Request(base + path, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=90) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
rd = {"endpoint_id": inputs.get("endpoint_id")}
|
||||
if inputs.get("incident_id"):
|
||||
rd["incident_id"] = inputs["incident_id"]
|
||||
print(json.dumps(post("/endpoints/unisolate", rd)))
|
||||
|
||||
|
||||
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)
|
||||
Reference in New Issue
Block a user