Packages
A stateless Elixir wrapper for the Logpoint SIEM API. Covers searching, incidents, alert rules, user-defined lists, and repos with builder patterns for rules and notifications.
Current section
Files
Jump to
Current section
Files
lib/logpoint_api.ex
defmodule LogpointApi do
@moduledoc """
Elixir library for interacting with the Logpoint API.
This library provides a simple, stateless interface to the Logpoint API.
All functions take credentials as parameters and make direct HTTP requests.
## Example Usage
```elixir
# Define credentials
credentials = %{
ip: "127.0.0.1",
username: "admin",
secret_key: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
verify_ssl: false # optional, defaults to false for self-signed certs
}
# Create a query
query = %LogpointApi.Query{
query: "user=*",
limit: 100,
repos: ["127.0.0.1:5504"],
time_range: [1_714_986_600, 1_715_031_000]
}
# Run a complete search (get search_id + poll for results)
{:ok, result} = LogpointApi.run_search(credentials, query)
# Or do it step by step
{:ok, %{"search_id" => search_id}} = LogpointApi.get_search_id(credentials, query)
{:ok, result} = LogpointApi.get_search_result(credentials, search_id)
```
"""
alias LogpointApi.Core
alias LogpointApi.Incident
alias LogpointApi.IncidentComment
alias LogpointApi.IncidentCommentData
alias LogpointApi.IncidentIDs
alias LogpointApi.Query
alias LogpointApi.TimeRange
@typedoc """
Credentials for authenticating with the Logpoint API.
"""
@type credentials :: %{
ip: String.t(),
username: String.t(),
secret_key: String.t(),
verify_ssl: boolean()
}
@doc """
Run a complete search: submit query, poll for completion, and return results.
This is a convenience function that combines `get_search_id/2` and `get_search_result/2`
with automatic polling until the search completes.
"""
@spec run_search(credentials(), Query.t(), keyword()) :: {:ok, map()} | {:error, String.t()}
def run_search(credentials, %Query{} = query, opts \\ []) do
poll_interval = Keyword.get(opts, :poll_interval, 1000)
max_retries = Keyword.get(opts, :max_retries, 60)
with {:ok, %{"search_id" => search_id}} <- get_search_id(credentials, query) do
Core.poll_search_result(credentials, search_id, poll_interval, max_retries, query)
end
end
@doc """
Create a search and get its search id.
"""
@spec get_search_id(credentials(), Query.t()) :: {:ok, map()} | {:error, String.t()}
def get_search_id(credentials, %Query{} = query), do: Core.get_search_logs(credentials, query)
@doc """
Retrieve the search result of a specific search id.
"""
@spec get_search_result(credentials(), String.t()) :: {:ok, map()} | {:error, String.t()}
def get_search_result(credentials, search_id), do: Core.get_search_logs(credentials, %{search_id: search_id})
@doc """
Get user preferences from the Logpoint instance.
"""
@spec user_preference(credentials()) :: {:ok, map()} | {:error, String.t()}
def user_preference(credentials), do: Core.get_allowed_data(credentials, :user_preference)
@doc """
Get loginspects from the Logpoint instance.
"""
@spec loginspects(credentials()) :: {:ok, map()} | {:error, String.t()}
def loginspects(credentials), do: Core.get_allowed_data(credentials, :loginspects)
@doc """
Get logpoint repositories from the instance.
"""
@spec logpoint_repos(credentials()) :: {:ok, map()} | {:error, String.t()}
def logpoint_repos(credentials), do: Core.get_allowed_data(credentials, :logpoint_repos)
@doc """
Get devices from the Logpoint instance.
"""
@spec devices(credentials()) :: {:ok, map()} | {:error, String.t()}
def devices(credentials), do: Core.get_allowed_data(credentials, :devices)
@doc """
Get live searches from the Logpoint instance.
"""
@spec livesearches(credentials()) :: {:ok, map()} | {:error, String.t()}
def livesearches(credentials), do: Core.get_allowed_data(credentials, :livesearches)
@doc """
Get users from the Logpoint instance.
"""
@spec users(credentials()) :: {:ok, map()} | {:error, String.t()}
def users(credentials), do: Core.get_users(credentials)
@doc """
Get a specific incident and its related data.
"""
@spec get_data_from_incident(credentials(), Incident.t()) :: {:ok, map()} | {:error, String.t()}
def get_data_from_incident(credentials, %Incident{} = incident) do
Core.get_incident_info(credentials, incident)
end
@doc """
Get incident information by object ID and incident ID.
"""
@spec incident(credentials(), String.t(), String.t()) :: {:ok, map()} | {:error, String.t()}
def incident(credentials, incident_obj_id, incident_id) do
incident = Incident.new(incident_obj_id, incident_id)
Core.get_incident_info(credentials, incident)
end
@doc """
Get incidents within a time range.
"""
@spec incidents(credentials(), number(), number()) :: {:ok, map()} | {:error, String.t()}
def incidents(credentials, start_time, end_time) do
time_range = TimeRange.new(start_time, end_time)
Core.get_incident_info(credentials, :incidents, time_range)
end
@doc """
Get incident states within a time range.
"""
@spec incident_states(credentials(), number(), number()) :: {:ok, map()} | {:error, String.t()}
def incident_states(credentials, start_time, end_time) do
time_range = TimeRange.new(start_time, end_time)
Core.get_incident_info(credentials, :incident_states, time_range)
end
@doc """
Add comments to incidents.
Accepts either a map of %{"incident_id" => ["comment1", "comment2"]}
or an IncidentCommentData struct.
"""
@spec add_comments(credentials(), map() | IncidentCommentData.t()) :: {:ok, map()} | {:error, String.t()}
def add_comments(credentials, %IncidentCommentData{} = incident_comment_data),
do: Core.update_incident_state(credentials, "/add_incident_comment", incident_comment_data)
def add_comments(credentials, comments) when is_map(comments) and not is_struct(comments) do
comment_structs =
Enum.map(comments, fn {incident_id, comment_list} ->
IncidentComment.new(incident_id, comment_list)
end)
comment_data = IncidentCommentData.new("0.1", comment_structs)
add_comments(credentials, comment_data)
end
@doc """
Assign incidents to a user.
Accepts either a list of incident IDs or an IncidentIDs struct.
"""
@spec assign_incidents(credentials(), [String.t()] | IncidentIDs.t(), String.t()) ::
{:ok, map()} | {:error, String.t()}
def assign_incidents(credentials, %IncidentIDs{} = incident_ids, assignee_id) do
payload = Map.put(incident_ids, :new_assignee, assignee_id)
Core.update_incident_state(credentials, "/assign_incident", payload)
end
def assign_incidents(credentials, incident_ids, assignee_id) when is_list(incident_ids) do
incident_ids_struct = IncidentIDs.new("0.1", incident_ids)
assign_incidents(credentials, incident_ids_struct, assignee_id)
end
@doc """
Resolve incidents.
"""
@spec resolve_incidents(credentials(), [String.t()]) :: {:ok, map()} | {:error, String.t()}
def resolve_incidents(credentials, incident_ids) do
incident_ids_struct = IncidentIDs.new("0.1", incident_ids)
Core.update_incidents(credentials, :resolve, incident_ids_struct)
end
@doc """
Close incidents.
"""
@spec close_incidents(credentials(), [String.t()]) :: {:ok, map()} | {:error, String.t()}
def close_incidents(credentials, incident_ids) do
incident_ids_struct = IncidentIDs.new("0.1", incident_ids)
Core.update_incidents(credentials, :close, incident_ids_struct)
end
@doc """
Reopen incidents.
"""
@spec reopen_incidents(credentials(), [String.t()]) :: {:ok, map()} | {:error, String.t()}
def reopen_incidents(credentials, incident_ids) do
incident_ids_struct = IncidentIDs.new("0.1", incident_ids)
Core.update_incidents(credentials, :reopen, incident_ids_struct)
end
end