feat(ipinfo): add IPinfo Core API connector
IP enrichment (geolocation, ASN/network, privacy flags): lookup_ip, lookup_field, lookup_me, batch (code-first), and test_connection. Token auth via the `token` query parameter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
|||||||
|
id: ipinfo
|
||||||
|
name: IPinfo
|
||||||
|
version: 1.0.0
|
||||||
|
description: "IPinfo Core API — IP address enrichment: geolocation, ASN / network details, and privacy/network flags (hosting, mobile, anycast, satellite)."
|
||||||
|
changelog: "1.0.0 — Initial release: IP lookup, single-field lookup, own IP, batch, and connectivity test."
|
||||||
|
category: enrichment
|
||||||
|
|
||||||
|
config_schema:
|
||||||
|
properties:
|
||||||
|
base_url:
|
||||||
|
type: string
|
||||||
|
description: IPinfo Core API base URL
|
||||||
|
default: https://api.ipinfo.io
|
||||||
|
token:
|
||||||
|
type: string
|
||||||
|
description: IPinfo API access token (Account → Token)
|
||||||
|
x-soar-sensitive: true
|
||||||
|
required:
|
||||||
|
- token
|
||||||
|
|
||||||
|
# IPinfo authenticates with the access token as the `token` query parameter.
|
||||||
|
auth:
|
||||||
|
- id: apikey
|
||||||
|
type: api_key
|
||||||
|
in: query
|
||||||
|
name: token
|
||||||
|
value_template: "{{secret}}"
|
||||||
|
secret_field: token
|
||||||
|
|
||||||
|
commands:
|
||||||
|
- id: lookup_ip
|
||||||
|
name: ipinfo-lookup-ip
|
||||||
|
description: Full enrichment for an IP — geolocation, ASN/network, and privacy/network flags.
|
||||||
|
risk: read
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
ip: { type: string, description: "IPv4 or IPv6 address" }
|
||||||
|
required: [ip]
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
request:
|
||||||
|
method: GET
|
||||||
|
path: /lookup/{ip}
|
||||||
|
auth_ref: apikey
|
||||||
|
|
||||||
|
- id: lookup_field
|
||||||
|
name: ipinfo-lookup-field
|
||||||
|
description: A single field for an IP (e.g. city, country, hostname, as).
|
||||||
|
risk: read
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
ip: { type: string, description: "IP address" }
|
||||||
|
field: { type: string, description: "Field name, e.g. city, country, hostname, as" }
|
||||||
|
required: [ip, field]
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
request:
|
||||||
|
method: GET
|
||||||
|
path: /lookup/{ip}/{field}
|
||||||
|
auth_ref: apikey
|
||||||
|
|
||||||
|
- id: lookup_me
|
||||||
|
name: ipinfo-lookup-me
|
||||||
|
description: Details for the IP address making the request.
|
||||||
|
risk: read
|
||||||
|
inputs_schema:
|
||||||
|
properties: {}
|
||||||
|
required: []
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
request:
|
||||||
|
method: GET
|
||||||
|
path: /lookup/me
|
||||||
|
auth_ref: apikey
|
||||||
|
|
||||||
|
# Code-first: the batch endpoint takes a raw JSON array body, which the
|
||||||
|
# form-based generator (object body) cannot produce. See scripts/batch.py.
|
||||||
|
- id: batch
|
||||||
|
name: ipinfo-batch
|
||||||
|
description: Look up multiple IPs (or IP/field paths) in a single request.
|
||||||
|
risk: read
|
||||||
|
inputs_schema:
|
||||||
|
properties:
|
||||||
|
ips: { type: string, description: "Comma-separated IPs or lookup paths, e.g. '8.8.8.8,1.1.1.1,8.8.4.4/country'" }
|
||||||
|
required: [ips]
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
|
||||||
|
- id: test_connection
|
||||||
|
name: ipinfo-test-connection
|
||||||
|
description: "Verify connectivity and credentials (used by the Test button)."
|
||||||
|
risk: read
|
||||||
|
inputs_schema:
|
||||||
|
properties: {}
|
||||||
|
required: []
|
||||||
|
outputs_schema: { properties: {} }
|
||||||
|
request:
|
||||||
|
method: GET
|
||||||
|
path: /lookup/me
|
||||||
|
auth_ref: apikey
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import json, os, sys, urllib.request, urllib.parse, urllib.error
|
||||||
|
|
||||||
|
SECRETS = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||||
|
INPUTS = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||||
|
BASE = SECRETS.get("base_url", "https://api.ipinfo.io").rstrip("/")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
token = SECRETS.get("token", "")
|
||||||
|
ips = [x.strip() for x in str(INPUTS.get("ips", "")).split(",") if x.strip()]
|
||||||
|
if not ips:
|
||||||
|
print(json.dumps({"error": "ips is required"}))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# IPinfo's POST /batch expects a raw JSON array of IPs / lookup paths.
|
||||||
|
url = BASE + "/batch?" + urllib.parse.urlencode({"token": token})
|
||||||
|
data = json.dumps(ips).encode("utf-8")
|
||||||
|
headers = {"Content-Type": "application/json", "Accept": "application/json"}
|
||||||
|
req = urllib.request.Request(url, data=data, headers=headers, method="POST")
|
||||||
|
with urllib.request.urlopen(req, timeout=30) as r:
|
||||||
|
raw = r.read()
|
||||||
|
print(json.dumps(json.loads(raw) if raw else {}))
|
||||||
|
|
||||||
|
|
||||||
|
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