Class: EndpointSecurity::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/endpoint_security/client.rb

Overview

Owns an Endpoint Security client and dispatches subscribed messages.

Constant Summary collapse

PATH_TYPES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Native values for path mute kinds.

{ prefix: 0, literal: 1, target_prefix: 2, target_literal: 3 }.freeze
INVERSION_TYPES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Native values for mute inversion kinds.

{ process: 0, path: 1, target_path: 2 }.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mute_self: true, subscribe: nil, probe: :lazy) ⇒ Client

Raises:

  • (ArgumentError)


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/endpoint_security/client.rb', line 32

def initialize(mute_self: true, subscribe: nil, probe: :lazy, **)
  raise ArgumentError, "probe must be :lazy, :eager, or :off" unless i[lazy eager off].include?(probe.to_sym)

  __native_initialize(mute_self: mute_self, **)
  initialized = false
  begin
    @probe = probe.to_sym
    @handlers = {}
    @subscriptions = []
    @errors = 0
    @reported_timeouts = 0
    @running = false
    mute_process(pid: ::Process.pid) if mute_self
    if @probe == :eager
      EventType.all.each do |event|
        Availability.probe_cache[event] = probe_event(event) if Availability.supported_event?(event)
      end
    end
    self.subscribe(subscribe) if subscribe
    initialized = true
  ensure
    __native_close unless initialized
  end
end

Class Method Details

.open {|client| ... } ⇒ Object

Yields:

  • (client)

Returns:

  • (Object)


11
12
13
14
15
16
17
18
# File 'lib/endpoint_security/client.rb', line 11

def open(**)
  client = new(**)
  return client unless block_given?

  yield client
ensure
  client&.close if block_given?
end

Instance Method Details

#__native_close ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Calls the native close implementation.



26
# File 'lib/endpoint_security/client.rb', line 26

alias __native_close close

#__native_initialize ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Calls the native constructor.



23
# File 'lib/endpoint_security/client.rb', line 23

alias __native_initialize initialize

#__native_stats ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Calls the native statistics implementation.



29
# File 'lib/endpoint_security/client.rb', line 29

alias __native_stats stats

#clear_cache ⇒ Object

Clears the Endpoint Security authorization cache.



204
# File 'lib/endpoint_security/client.rb', line 204

def clear_cache = __clear_cache

#close ⇒ nil

Returns:

  • (nil)


153
154
155
156
157
158
159
160
161
162
# File 'lib/endpoint_security/client.rb', line 153

def close
  if @thread == ::Thread.current && @dispatching
    @running = false
    @close_after_dispatch = true
    return
  end

  stop
  __native_close
end

#invert_muting(type) ⇒ Object

Inverts muting for type.



207
208
209
# File 'lib/endpoint_security/client.rb', line 207

def invert_muting(type)
  __invert_muting(INVERSION_TYPES.fetch(type.to_sym))
end

#mute_all_es_clients! ⇒ Client

Mutes other Endpoint Security clients when their first event is observed.

Returns:



118
119
120
121
# File 'lib/endpoint_security/client.rb', line 118

def mute_all_es_clients!
  @mute_es_clients = true
  self
end

#mute_path(path, type: :prefix) ⇒ Object

Mutes events for path.



177
178
# File 'lib/endpoint_security/client.rb', line 177

def mute_path(path, type: :prefix) = change_path_mute(:mute, path, type, [])
# Removes a path mute.

#mute_path_events(path, *events, type: :prefix) ⇒ Object

Mutes selected events for path.



181
182
# File 'lib/endpoint_security/client.rb', line 181

def mute_path_events(path, *events, type: :prefix) = change_path_mute(:mute, path, type, events)
# Removes selected event mutes for +path+.

#mute_process(token = nil, pid: nil) ⇒ Object

Mutes a process by audit token or PID.



186
187
188
# File 'lib/endpoint_security/client.rb', line 186

def mute_process(token = nil, pid: nil)
  change_process_mute(:mute, token || (__audit_token_for_pid(pid) if pid), [])
end

#mute_process_events(token, *events) ⇒ Object

Mutes selected events for a process.



196
197
# File 'lib/endpoint_security/client.rb', line 196

def mute_process_events(token, *events) = change_process_mute(:mute, token, events)
# Removes selected event mutes for a process.

#muted_paths ⇒ Array<Hash>

Returns copied path mute entries.

Returns:

  • (Array<Hash>) —

    copied path mute entries



217
218
219
# File 'lib/endpoint_security/client.rb', line 217

def muted_paths
  __muted_paths.map { |item| item.merge(type: PATH_TYPES.key(item[:type]) || item[:type]) }
end

#muted_processes ⇒ Array<Hash>

Returns copied process mute entries.

Returns:

  • (Array<Hash>) —

    copied process mute entries



222
# File 'lib/endpoint_security/client.rb', line 222

def muted_processes = __muted_processes

#muting_inverted?(type) ⇒ Boolean

Returns whether muting for type is inverted.

Returns:

  • (Boolean) —

    whether muting for type is inverted



212
213
214
# File 'lib/endpoint_security/client.rb', line 212

def muting_inverted?(type)
  __muting_inverted(INVERSION_TYPES.fetch(type.to_sym))
end

#on(event, &handler) ⇒ Client

Returns:

Raises:

  • (ArgumentError)


97
98
99
100
101
102
# File 'lib/endpoint_security/client.rb', line 97

def on(event, &handler)
  raise ArgumentError, "handler block is required" unless handler

  @handlers[event.to_sym] = handler
  self
end

#on_error(&handler) ⇒ Client

Returns:



105
106
107
108
# File 'lib/endpoint_security/client.rb', line 105

def on_error(&handler)
  @error_handler = handler
  self
end

#on_timeout(&handler) ⇒ Client

Returns:



111
112
113
114
# File 'lib/endpoint_security/client.rb', line 111

def on_timeout(&handler)
  @timeout_handler = handler
  self
end

#run ⇒ Client

Returns:



124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/endpoint_security/client.rb', line 124

def run
  @running = true
  wakeup = IO.for_fd(__wakeup_fd, autoclose: false)
  while @running && !closed?
    wakeup.wait_readable(0.1)
    __drain.each { |message| dispatch(message) }
    report_timeouts
  end
  self
ensure
  @running = false
end

#start ⇒ Thread

Returns:

  • (Thread)


138
139
140
141
142
# File 'lib/endpoint_security/client.rb', line 138

def start
  return @thread if @thread&.alive?

  @thread = ::Thread.new { run }
end

#stats ⇒ Hash

Returns:

  • (Hash)


165
166
167
# File 'lib/endpoint_security/client.rb', line 165

def stats
  __native_stats.merge(errors: @errors)
end

#stop ⇒ Client

Returns:



145
146
147
148
149
150
# File 'lib/endpoint_security/client.rb', line 145

def stop
  @running = false
  __wake unless closed?
  @thread&.join unless @thread == ::Thread.current
  self
end

#subscribe(*events, skip_unsupported: true, **_options) ⇒ Array<Symbol>

Returns:

  • (Array<Symbol>)


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/endpoint_security/client.rb', line 58

def subscribe(*events, skip_unsupported: true, **_options)
  events = events.flatten.map(&:to_sym) - @subscriptions
  unsupported = events.reject { |event| supported_event?(event) }
  if !skip_unsupported && !unsupported.empty?
    raise UnsupportedEventError, "unsupported events: #{unsupported.join(", ")}"
  end

  events -= unsupported
  return @subscriptions if events.empty?

  begin
    (events.map { |event| EventType.value(event) })
  rescue SubscriptionError => e
    failed = events.reject { |event| probe_event(event) }
    failed = events if failed.empty?
    raise SubscriptionError, "failed to subscribe: #{failed.join(", ")} (#{e.message})"
  end
  @subscriptions |= events
end

#subscriptions ⇒ Array<Symbol>

Returns subscriptions reported by Endpoint Security.

Returns:

  • (Array<Symbol>) —

    subscriptions reported by Endpoint Security



94
# File 'lib/endpoint_security/client.rb', line 94

def subscriptions = __subscriptions

#unmute_all_paths ⇒ Object

Removes every source-path mute.



200
201
# File 'lib/endpoint_security/client.rb', line 200

def unmute_all_paths = __unmute_all_paths(false)
# Removes every target-path mute.

#unmute_all_target_paths ⇒ Object

Removes every target-path mute.



202
203
# File 'lib/endpoint_security/client.rb', line 202

def unmute_all_target_paths = __unmute_all_paths(true)
# Clears the Endpoint Security authorization cache.

#unmute_path(path, type: :prefix) ⇒ Object

Removes a path mute.



179
180
# File 'lib/endpoint_security/client.rb', line 179

def unmute_path(path, type: :prefix) = change_path_mute(:unmute, path, type, [])
# Mutes selected +events+ for +path+.

#unmute_path_events(path, *events, type: :prefix) ⇒ Object

Removes selected event mutes for path.



183
# File 'lib/endpoint_security/client.rb', line 183

def unmute_path_events(path, *events, type: :prefix) = change_path_mute(:unmute, path, type, events)

#unmute_process(token = nil, pid: nil) ⇒ Object

Removes a process mute by audit token or PID.



191
192
193
# File 'lib/endpoint_security/client.rb', line 191

def unmute_process(token = nil, pid: nil)
  change_process_mute(:unmute, token || (__audit_token_for_pid(pid) if pid), [])
end

#unmute_process_events(token, *events) ⇒ Object

Removes selected event mutes for a process.



198
199
# File 'lib/endpoint_security/client.rb', line 198

def unmute_process_events(token, *events) = change_process_mute(:unmute, token, events)
# Removes every source-path mute.

#unsubscribe(*events) ⇒ Array<Symbol>

Returns remaining subscriptions.

Returns:

  • (Array<Symbol>) —

    remaining subscriptions



79
80
81
82
83
84
85
# File 'lib/endpoint_security/client.rb', line 79

def unsubscribe(*events)
  events = events.flatten.map(&:to_sym)
  return @subscriptions if events.empty?

  __unsubscribe(events.map { |event| EventType.value(event) })
  @subscriptions -= events
end

#unsubscribe_all ⇒ Array

Returns empty subscription list.

Returns:

  • (Array) —

    empty subscription list



88
89
90
91
# File 'lib/endpoint_security/client.rb', line 88

def unsubscribe_all
  __unsubscribe(nil)
  @subscriptions.clear
end