Module: PryRemoteEm::Server
- Includes:
- Proto
- Defined in:
- lib/pry-remote-em/server.rb,
lib/pry-remote-em/server/shell_cmd.rb
Defined Under Namespace
Modules: ShellCmd
Class Method Summary
collapse
Instance Method Summary
collapse
Methods included from Proto
#receive_banner, #receive_data, #receive_object, #receive_prompt, #receive_proxy_connection, #receive_register_server, #receive_server_list, #receive_server_reload_list, #receive_shell_result, #receive_start_tls, #receive_unregister_server, #send_auth, #send_banner, #send_clear_buffer, #send_completion, #send_heatbeat, #send_msg, #send_msg_bcast, #send_object, #send_prompt, #send_proxy_connection, #send_raw, #send_register_server, #send_server_list, #send_server_reload_list, #send_shell_cmd, #send_shell_data, #send_shell_result, #send_shell_sig, #send_start_tls, #send_unregister_server
Class Method Details
.peers(obj = nil) ⇒ Object
The list of pry-remote-em connections for a given object, or the list of all pry-remote-em connections for this process. The peer list is used when broadcasting messages between connections.
115
116
117
118
|
# File 'lib/pry-remote-em/server.rb', line 115
def peers(obj = nil)
@peers ||= {}
obj.nil? ? @peers.values.flatten : (@peers[obj] ||= [])
end
|
.register(obj, peer) ⇒ Object
Record the association between a given object and a given pry-remote-em connection.
121
122
123
|
# File 'lib/pry-remote-em/server.rb', line 121
def register(obj, peer)
peers(obj).tap { |plist| plist.include?(peer) || plist.push(peer) }
end
|
.run(options = {}, &block) ⇒ Object
Start a pry-remote-em server
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
# File 'lib/pry-remote-em/server.rb', line 92
def run(options = {}, &block)
description = options.dup
description[:target] ||= PryRemoteEm::Sandbox.new
description[:host] ||= ENV['PRYEMHOST'].nil? || ENV['PRYEMHOST'].empty? ? DEFAULT_SERVER_HOST : ENV['PRYEMHOST']
determine_port_and_tries(description)
determine_name(description)
description[:id] ||= SecureRandom.uuid
description[:logger] ||= ::Logger.new(STDERR)
description[:external_url] ||= ENV['PRYEMURL'] || "#{description[:tls] ? 'pryems' : 'pryem'}://#{description[:host]}:#{description[:port]}/"
description[:details] ||= {}
description[:allow_shell_cmds] = true if description[:allow_shell_cmds].nil?
description[:heartbeat_interval] ||= ENV['PRYEMHBSEND'].nil? || ENV['PRYEMHBSEND'].empty? ? HEARTBEAT_SEND_INTERVAL : ENV['PRYEMHBSEND']
description[:urls] = expand_url(description[:external_url])
description[:server] = start_server(description, &block)
description[:logger].info("[pry-remote-em] listening for connections on #{description[:external_url]}")
PryRemoteEm.servers[description[:id]] = description
register_in_broker(description)
return description
end
|
.unregister(obj, peer) ⇒ Object
Remove the association between a given object and a given pry-remote-em connection.
126
127
128
|
# File 'lib/pry-remote-em/server.rb', line 126
def unregister(obj, peer)
peers(obj).tap {|plist| true while plist.delete(peer) }
end
|
Instance Method Details
#after_auth(&blk) ⇒ Object
424
425
426
427
|
# File 'lib/pry-remote-em/server.rb', line 424
def after_auth(&blk)
@after_auth.push(blk)
end
|
#auth_attempt {|user, ip| ... } ⇒ Object
Registers a block to call when authentication is attempted.
448
449
450
451
452
453
|
# File 'lib/pry-remote-em/server.rb', line 448
def auth_attempt(*args, &blk)
block_given? ? @auth_attempt_cbs << blk : @auth_attempts.push(args)
while (auth_data = @auth_attempts.shift)
@auth_attempt_cbs.each { |cb| cb.call(*auth_data) }
end
end
|
#auth_fail {|user, ip| ... } ⇒ Object
Registers a block to call when authentication fails.
460
461
462
463
464
465
|
# File 'lib/pry-remote-em/server.rb', line 460
def auth_fail(*args, &blk)
block_given? ? @auth_fail_cbs << blk : @auth_fails.push(args)
while (fail_data = @auth_fails.shift)
@auth_fail_cbs.each { |cb| cb.call(*fail_data) }
end
end
|
#auth_ok {|user, ip| ... } ⇒ Object
Registers a block to call when authentication succeeds.
472
473
474
475
476
477
|
# File 'lib/pry-remote-em/server.rb', line 472
def auth_ok(*args, &blk)
block_given? ? @auth_ok_cbs << blk : @auth_oks.push(args)
while (ok_data = @auth_oks.shift)
@auth_ok_cbs.each { |cb| cb.call(*ok_data) }
end
end
|
#authenticated! ⇒ Object
403
404
405
406
407
|
# File 'lib/pry-remote-em/server.rb', line 403
def authenticated!
while (aa = @after_auth.shift)
aa.call
end
end
|
#completion_proc=(compl) ⇒ Object
503
504
505
|
# File 'lib/pry-remote-em/server.rb', line 503
def completion_proc=(compl)
@compl_proc = compl
end
|
511
512
513
|
# File 'lib/pry-remote-em/server.rb', line 511
def flush
true
end
|
#initialize(opts = {}) ⇒ Object
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
|
# File 'lib/pry-remote-em/server.rb', line 218
def initialize(opts = {})
@obj = opts[:target]
@opts = opts
@allow_shell_cmds = opts[:allow_shell_cmds]
@log = opts[:logger] || ::Logger.new(STDERR)
@auth_attempt_cbs = []
@auth_attempts = []
@auth_fail_cbs = []
@auth_fails = []
@auth_ok_cbs = []
@auth_oks = []
@auth_tries = 5
@after_auth = []
return unless (a = opts[:auth])
if a.is_a?(Proc)
return fail("auth handler Procs must take two arguments not (#{a.arity})") unless a.arity == 2
@auth = a
elsif a.respond_to?(:call)
return fail("auth handler must take two arguments not (#{a.method(:call).arity})") unless a.method(:call).arity == 2
@auth = a
else
return error('auth handler objects must respond to :call, or :[]') unless a.respond_to?(:[])
@auth = lambda {|u,p| a[u] && a[u] == p }
end
end
|
290
291
292
293
294
295
|
# File 'lib/pry-remote-em/server.rb', line 290
def peer_ip
return @peer_ip if @peer_ip
return '' if get_peername.nil?
@peer_port, @peer_ip = Socket.unpack_sockaddr_in(get_peername)
@peer_ip
end
|
#peer_port ⇒ Object
297
298
299
300
301
302
|
# File 'lib/pry-remote-em/server.rb', line 297
def peer_port
return @peer_port if @peer_port
return '' if get_peername.nil?
@peer_port, @peer_ip = Socket.unpack_sockaddr_in(get_peername)
@peer_port
end
|
#post_init ⇒ Object
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
|
# File 'lib/pry-remote-em/server.rb', line 258
def post_init
@lines = []
@auth_required = @auth
@port, @ip = Socket.unpack_sockaddr_in(get_peername)
@log.info("[pry-remote-em] received client connection from #{@ip}:#{@port}")
send_banner("PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}")
need_new_line = false
if @opts[:details].any?
send_raw("\nServer details:\n#{@opts[:details].map { |key, value| " #{key}: #{value}" } * "\n"}\n")
need_new_line = true
end
if PryRemoteEm::Metrics.any?
send_raw("\nServer metrics:\n#{PryRemoteEm::Metrics.list.map { |key, value| " #{key}: #{value}" } * "\n"}\n")
need_new_line = true
end
send_raw("\n") if need_new_line
@log.info("#{url} PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}")
@opts[:tls] ? start_tls : (@auth_required && send_auth(false))
PryRemoteEm::Server.register(@obj, self)
end
|
#print(val) ⇒ Object
Also known as:
write
493
494
495
|
# File 'lib/pry-remote-em/server.rb', line 493
def print(val)
@auth_required ? (after_auth { send_raw(val) }) : send_raw(val)
end
|
#puts(data = '') ⇒ Object
498
499
500
501
|
# File 'lib/pry-remote-em/server.rb', line 498
def puts(data = '')
s = data.to_s
print(s[0] == "\n" ? s : s + "\n")
end
|
#readline(prompt) ⇒ Object
Methods that make Server compatible with Pry
485
486
487
488
489
490
491
|
# File 'lib/pry-remote-em/server.rb', line 485
def readline(prompt)
@last_prompt = prompt
@auth_required ? (after_auth { send_prompt(prompt) }) : send_prompt(prompt)
return @lines.shift unless @lines.empty?
@waiting = Fiber.current
return Fiber.yield
end
|
#receive_auth(user, pass) ⇒ Object
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
|
# File 'lib/pry-remote-em/server.rb', line 334
def receive_auth(user, pass)
return send_auth(true) if !@auth || !@auth_required
return send_auth('auth data must include a user and pass') if user.nil? || pass.nil?
auth_attempt(user, peer_ip)
unless (@auth_required = !@auth.call(user, pass))
@user = user
auth_ok(user, peer_ip)
authenticated!
else
auth_fail(user, peer_ip)
if @auth_tries <= 0
msg = 'max authentication attempts reached'
send_auth(msg)
@log.debug("[pry-remote-em] #{msg} (#{peer_ip}:#{peer_port})")
return close_connection_after_writing
end
@auth_tries -= 1
end
return send_auth(!@auth_required)
end
|
#receive_clear_buffer ⇒ Object
304
305
306
307
308
|
# File 'lib/pry-remote-em/server.rb', line 304
def receive_clear_buffer
@opts[:pry].eval_string.replace('')
@last_prompt = @opts[:pry].select_prompt
send_last_prompt
end
|
#receive_completion(c) ⇒ Object
329
330
331
332
|
# File 'lib/pry-remote-em/server.rb', line 329
def receive_completion(c)
return if require_auth
send_completion(@compl_proc.call(c))
end
|
#receive_msg(m) ⇒ Object
355
356
357
358
359
|
# File 'lib/pry-remote-em/server.rb', line 355
def receive_msg(m)
return if require_auth
peers.each { |peer| peer.send_message(m, @user) }
send_last_prompt
end
|
#receive_msg_bcast(mb) ⇒ Object
361
362
363
364
365
|
# File 'lib/pry-remote-em/server.rb', line 361
def receive_msg_bcast(mb)
return if require_auth
peers(:all).each { |peer| peer.send_bmessage(mb, @user) }
send_last_prompt
end
|
#receive_raw(d) ⇒ Object
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
|
# File 'lib/pry-remote-em/server.rb', line 310
def receive_raw(d)
return if require_auth
return send_last_prompt if d.nil?
if d.empty?
@lines.push('')
else
lines = d.split("\n")
@lines.push(*lines)
end
if @waiting
f, @waiting = @waiting, nil
f.resume(@lines.shift)
end
end
|
#receive_shell_cmd(cmd) ⇒ Object
367
368
369
370
371
372
373
374
375
376
377
378
|
# File 'lib/pry-remote-em/server.rb', line 367
def receive_shell_cmd(cmd)
return if require_auth
unless @allow_shell_cmds
puts "\033[1mshell commands are not allowed by this server\033[0m"
@log.error("refused to execute shell command '#{cmd}' for #{@user} (#{peer_ip}:#{peer_port})")
send_shell_result(-1)
send_last_prompt
else
@log.warn("executing shell command '#{cmd}' for #{@user} (#{peer_ip}:#{peer_port})")
@shell_cmd = EM.popen3(cmd, ShellCmd, self)
end
end
|
#receive_shell_data(d) ⇒ Object
380
381
382
383
|
# File 'lib/pry-remote-em/server.rb', line 380
def receive_shell_data(d)
return if require_auth
@shell_cmd.send_data(d)
end
|
#receive_shell_sig(type) ⇒ Object
385
386
387
388
|
# File 'lib/pry-remote-em/server.rb', line 385
def receive_shell_sig(type)
return if require_auth
@shell_cmd.close_connection if type == :int
end
|
#receive_unknown(j) ⇒ Object
390
391
392
393
394
395
|
# File 'lib/pry-remote-em/server.rb', line 390
def receive_unknown(j)
return if require_auth
warn "received unexpected data: #{j.inspect}"
send_error("received unexpected data: #{j.inspect}")
send_last_prompt
end
|
#require_auth ⇒ Object
397
398
399
400
401
|
# File 'lib/pry-remote-em/server.rb', line 397
def require_auth
return false if !@auth_required
send_auth(false)
true
end
|
#send_bmessage(msg, from = nil) ⇒ Object
Sends a chat message to the client.
436
437
438
439
|
# File 'lib/pry-remote-em/server.rb', line 436
def send_bmessage(msg, from = nil)
msg = "#{msg} (@#{from})" unless from.nil?
@auth_required ? (after_auth {send_msg_bcast(msg)}) : send_msg_bcast(msg)
end
|
#send_error(msg) ⇒ Object
479
480
481
|
# File 'lib/pry-remote-em/server.rb', line 479
def send_error(msg)
puts "\033[31m#{msg}\033[0m"
end
|
#send_last_prompt ⇒ Object
420
421
422
|
# File 'lib/pry-remote-em/server.rb', line 420
def send_last_prompt
@auth_required ? (after_auth { send_prompt(@last_prompt) }) : send_prompt(@last_prompt)
end
|
#send_message(msg, from = nil) ⇒ Object
Sends a chat message to the client.
430
431
432
433
|
# File 'lib/pry-remote-em/server.rb', line 430
def send_message(msg, from = nil)
msg = "#{msg} (@#{from})" unless from.nil?
@auth_required ? (after_auth {send_msg(msg)}) : send_msg(msg)
end
|
#ssl_handshake_completed ⇒ Object
285
286
287
288
|
# File 'lib/pry-remote-em/server.rb', line 285
def ssl_handshake_completed
@log.info("[pry-remote-em] TLS connection established (#{peer_ip}:#{peer_port})")
send_auth(false) if @auth_required
end
|
#start_tls ⇒ Object
280
281
282
283
|
# File 'lib/pry-remote-em/server.rb', line 280
def start_tls
@log.debug("[pry-remote-em] starting TLS (#{peer_ip}:#{peer_port})")
super(@opts[:tls].is_a?(Hash) ? @opts[:tls] : {})
end
|
#tty? ⇒ Boolean
507
508
509
|
# File 'lib/pry-remote-em/server.rb', line 507
def tty?
true end
|
409
410
411
412
|
# File 'lib/pry-remote-em/server.rb', line 409
def unbind
PryRemoteEm::Server.unregister(@obj, self)
@log.debug("[pry-remote-em] remote session terminated (#{@ip}:#{@port})")
end
|
253
254
255
256
|
# File 'lib/pry-remote-em/server.rb', line 253
def url
port, host = Socket.unpack_sockaddr_in(get_sockname)
"#{@opts[:tls] ? 'pryems' : 'pryem'}://#{host}:#{port}/"
end
|