pwn 0.5.479 → 0.5.481
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/Gemfile +1 -1
- data/README.md +3 -3
- data/lib/pwn/plugins/jira_data_center.rb +79 -84
- data/lib/pwn/plugins/repl.rb +135 -51
- data/lib/pwn/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f8f0ace17ae36a1a8e60fd015ad3c0a37dcaa22fd3490806b4fc033bd974ae70
|
|
4
|
+
data.tar.gz: 4a3b5eb17658a0a7c63e6e49bd87cad5740112ed1c2d77207fd0cde9949a50d6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d97493c22667ef54489045fd1bdd5ff8940701fa266e923849f8784feacc546be605154bc215a15823b9c424a4ba025e6bd95d3a1b3e86eba3d70987bc55c6c0
|
|
7
|
+
data.tar.gz: 0636daf478dff9780efe1b14478d40d06e109927c955d8d8c50f8c1c8e5c1bd7faaad9cfc8f98254084f4f384cdaa90c4698d563e57d386be38449193600c2e4
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -37,7 +37,7 @@ $ cd /opt/pwn
|
|
|
37
37
|
$ ./install.sh
|
|
38
38
|
$ ./install.sh ruby-gem
|
|
39
39
|
$ pwn
|
|
40
|
-
pwn[v0.5.
|
|
40
|
+
pwn[v0.5.481]:001 >>> PWN.help
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
[](https://youtu.be/G7iLUY4FzsI)
|
|
@@ -52,7 +52,7 @@ $ rvm use ruby-3.4.4@pwn
|
|
|
52
52
|
$ gem uninstall --all --executables pwn
|
|
53
53
|
$ gem install --verbose pwn
|
|
54
54
|
$ pwn
|
|
55
|
-
pwn[v0.5.
|
|
55
|
+
pwn[v0.5.481]:001 >>> PWN.help
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
If you're using a multi-user install of RVM do:
|
|
@@ -62,7 +62,7 @@ $ rvm use ruby-3.4.4@pwn
|
|
|
62
62
|
$ rvmsudo gem uninstall --all --executables pwn
|
|
63
63
|
$ rvmsudo gem install --verbose pwn
|
|
64
64
|
$ pwn
|
|
65
|
-
pwn[v0.5.
|
|
65
|
+
pwn[v0.5.481]:001 >>> PWN.help
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
PWN periodically upgrades to the latest version of Ruby which is reflected in `/opt/pwn/.ruby-version`. The easiest way to upgrade to the latest version of Ruby from a previous PWN installation is to run the following script:
|
|
@@ -220,65 +220,85 @@ module PWN
|
|
|
220
220
|
epic_name = opts[:epic_name]
|
|
221
221
|
raise 'ERROR: epic_name cannot be nil when issue_type is :epic.' if issue_type == :epic && epic_name.nil?
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
223
|
+
# Attempt create, dynamically omit unlicensed fields on failure
|
|
224
|
+
create_attempts, get_issue_attempts = 1
|
|
225
|
+
max_create_attempts, max_get_issue_attempts = 7
|
|
226
|
+
created_issue = nil
|
|
227
|
+
begin
|
|
228
|
+
http_body = {
|
|
229
|
+
fields: {
|
|
230
|
+
project: {
|
|
231
|
+
key: project_key
|
|
232
|
+
},
|
|
233
|
+
summary: summary,
|
|
234
|
+
issuetype: {
|
|
235
|
+
name: issue_type.to_s.capitalize
|
|
236
|
+
},
|
|
237
|
+
"#{epic_name_field_key}": epic_name,
|
|
238
|
+
description: description
|
|
239
|
+
}
|
|
234
240
|
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
http_body[:fields].merge!(additional_fields[:fields])
|
|
238
|
-
|
|
239
|
-
issue_resp = rest_call(
|
|
240
|
-
http_method: :post,
|
|
241
|
-
rest_call: 'issue',
|
|
242
|
-
http_body: http_body
|
|
243
|
-
)
|
|
244
|
-
issue = issue_resp[:key]
|
|
245
241
|
|
|
246
|
-
|
|
247
|
-
attachments.each do |attachment|
|
|
248
|
-
raise "ERROR: #{attachment} not found." unless File.exist?(attachment)
|
|
242
|
+
http_body[:fields].merge!(additional_fields[:fields])
|
|
249
243
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
244
|
+
issue_resp = rest_call(
|
|
245
|
+
http_method: :post,
|
|
246
|
+
rest_call: 'issue',
|
|
247
|
+
http_body: http_body
|
|
248
|
+
)
|
|
249
|
+
issue = issue_resp[:key]
|
|
250
|
+
|
|
251
|
+
if attachments.any?
|
|
252
|
+
attachments.each do |attachment|
|
|
253
|
+
raise "ERROR: #{attachment} not found." unless File.exist?(attachment)
|
|
254
|
+
|
|
255
|
+
http_body = {
|
|
256
|
+
multipart: true,
|
|
257
|
+
file: File.new(attachment, 'rb')
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
rest_call(
|
|
261
|
+
http_method: :post,
|
|
262
|
+
rest_call: "issue/#{issue}/attachments",
|
|
263
|
+
http_body: http_body
|
|
264
|
+
)
|
|
265
|
+
end
|
|
266
|
+
end
|
|
254
267
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
268
|
+
if comment
|
|
269
|
+
issue_comment(
|
|
270
|
+
issue: issue,
|
|
271
|
+
comment_action: :add,
|
|
272
|
+
comment: comment
|
|
259
273
|
)
|
|
260
274
|
end
|
|
261
|
-
end
|
|
262
275
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
comment: comment
|
|
268
|
-
)
|
|
269
|
-
end
|
|
276
|
+
begin
|
|
277
|
+
created_issue = get_issue(issue: issue)
|
|
278
|
+
rescue RuntimeError
|
|
279
|
+
raise 'ERROR: Max attempts reached for retrieving created issue.' if get_issue_attempts > max_get_issue_attempts
|
|
270
280
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
raise 'ERROR: Max attempts reached for retrieving created issue.' if get_issue_attempts > max_get_issue_attempts
|
|
281
|
+
get_issue_attempts += 1
|
|
282
|
+
sleep 3
|
|
283
|
+
retry
|
|
284
|
+
end
|
|
285
|
+
rescue RestClient::ExceptionWithResponse => e
|
|
286
|
+
raise e if create_attempts >= max_create_attempts || e.response.body.to_s.empty?
|
|
278
287
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
288
|
+
json = JSON.parse(e.response.body, symbolize_names: true)
|
|
289
|
+
errors_hash = json[:errors] if json.is_a?(Hash)
|
|
290
|
+
if errors_hash.is_a?(Hash)
|
|
291
|
+
unlicensed_field_keys = errors_hash.select { |_fk, msg| msg.to_s =~ /unlicensed/i }.keys
|
|
292
|
+
if unlicensed_field_keys.any?
|
|
293
|
+
unlicensed_field_keys.each do |fk|
|
|
294
|
+
additional_fields[:fields].delete(fk.to_sym)
|
|
295
|
+
additional_fields[:fields].delete(fk.to_s)
|
|
296
|
+
end
|
|
297
|
+
@@logger.warn("Omitting unlicensed fields: #{unlicensed_field_keys.join(', ')} (attempt #{create_attempts}/#{max_create_attempts}). Retrying issue creation.") if defined?(@@logger)
|
|
298
|
+
create_attempts += 1
|
|
299
|
+
retry
|
|
300
|
+
end
|
|
301
|
+
end
|
|
282
302
|
end
|
|
283
303
|
|
|
284
304
|
created_issue
|
|
@@ -530,40 +550,15 @@ module PWN
|
|
|
530
550
|
end
|
|
531
551
|
end
|
|
532
552
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
epic_name: epic_name,
|
|
543
|
-
description: description,
|
|
544
|
-
additional_fields: additional_fields,
|
|
545
|
-
attachments: attachments
|
|
546
|
-
)
|
|
547
|
-
rescue RestClient::ExceptionWithResponse => e
|
|
548
|
-
raise e if attempt >= max_attempts || e.response.body.to_s.empty?
|
|
549
|
-
|
|
550
|
-
json = JSON.parse(e.response.body, symbolize_names: true)
|
|
551
|
-
errors_hash = json[:errors] if json.is_a?(Hash)
|
|
552
|
-
if errors_hash.is_a?(Hash)
|
|
553
|
-
unlicensed_field_keys = errors_hash.select { |_fk, msg| msg.to_s =~ /unlicensed/i }.keys
|
|
554
|
-
if unlicensed_field_keys.any?
|
|
555
|
-
unlicensed_field_keys.each do |fk|
|
|
556
|
-
additional_fields[:fields].delete(fk.to_sym)
|
|
557
|
-
additional_fields[:fields].delete(fk.to_s)
|
|
558
|
-
end
|
|
559
|
-
@@logger.warn("Omitting unlicensed fields: #{unlicensed_field_keys.join(', ')} (attempt #{attempt}/#{max_attempts}). Retrying clone.") if defined?(@@logger)
|
|
560
|
-
attempt += 1
|
|
561
|
-
retry
|
|
562
|
-
end
|
|
563
|
-
end
|
|
564
|
-
end
|
|
565
|
-
|
|
566
|
-
cloned_issue
|
|
553
|
+
create_issue(
|
|
554
|
+
project_key: project_key,
|
|
555
|
+
summary: summary,
|
|
556
|
+
issue_type: issue_type,
|
|
557
|
+
epic_name: epic_name,
|
|
558
|
+
description: description,
|
|
559
|
+
additional_fields: additional_fields,
|
|
560
|
+
attachments: attachments
|
|
561
|
+
)
|
|
567
562
|
rescue StandardError => e
|
|
568
563
|
raise e
|
|
569
564
|
end
|
data/lib/pwn/plugins/repl.rb
CHANGED
|
@@ -64,19 +64,10 @@ module PWN
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
region = PWN::Env[:plugins][:meshtastic][:channel][active_channel][:region]
|
|
70
|
-
topic = PWN::Env[:plugins][:meshtastic][:channel][active_channel][:topic]
|
|
71
|
-
channel_num = PWN::Env[:plugins][:meshtastic][:channel][active_channel][:channel_num]
|
|
67
|
+
ps1_proc = "#{name}[#{version}]:#{line_count} #{dchars} ".to_s.scrub
|
|
68
|
+
ps1_proc = '' if pi.config.pwn_mesh
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
name = "\001\e[1m\002\001\e[32m\002#{pi.config.prompt_name}\001\e[0m\002"
|
|
75
|
-
dchars = "\001\e[32m\002>>>\001\e[33m\002"
|
|
76
|
-
dchars = "\001\e[33m\002***\001\e[33m\002" if mode == :splat
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
"#{name}[#{version}]:#{line_count} #{dchars} ".to_s.scrub
|
|
70
|
+
ps1_proc
|
|
80
71
|
end
|
|
81
72
|
rescue StandardError => e
|
|
82
73
|
raise e
|
|
@@ -472,24 +463,77 @@ module PWN
|
|
|
472
463
|
# Init ncurses UI (idempotent) with separate RX (top) and TX (bottom) panes
|
|
473
464
|
Curses.init_screen
|
|
474
465
|
Curses.curs_set(0)
|
|
475
|
-
|
|
476
|
-
|
|
466
|
+
Curses.noecho
|
|
467
|
+
Curses.cbreak
|
|
468
|
+
Curses.crmode
|
|
469
|
+
Curses.ESCDELAY = 0
|
|
477
470
|
Curses.start_color
|
|
478
471
|
Curses.use_default_colors
|
|
479
472
|
|
|
473
|
+
mesh_highlight_colors = [
|
|
474
|
+
{ fg: Curses::COLOR_RED, bg: Curses::COLOR_WHITE },
|
|
475
|
+
{ fg: Curses::COLOR_GREEN, bg: Curses::COLOR_BLACK },
|
|
476
|
+
{ fg: Curses::COLOR_YELLOW, bg: Curses::COLOR_BLACK },
|
|
477
|
+
{ fg: Curses::COLOR_BLUE, bg: Curses::COLOR_WHITE },
|
|
478
|
+
{ fg: Curses::COLOR_CYAN, bg: Curses::COLOR_BLACK },
|
|
479
|
+
{ fg: Curses::COLOR_MAGENTA, bg: Curses::COLOR_WHITE },
|
|
480
|
+
{ fg: Curses::COLOR_WHITE, bg: Curses::COLOR_BLUE }
|
|
481
|
+
]
|
|
482
|
+
mesh_highlight_colors.each_with_index do |hash, idx|
|
|
483
|
+
color_id = idx + 1
|
|
484
|
+
color_fg = hash[:fg]
|
|
485
|
+
color_bg = hash[:bg]
|
|
486
|
+
Curses.init_pair(color_id, color_fg, color_bg)
|
|
487
|
+
end
|
|
488
|
+
PWN.const_set(:MeshColors, (1..mesh_highlight_colors.length).to_a)
|
|
489
|
+
PWN.const_set(:MeshLastPair, PWN::MeshColors.sample)
|
|
490
|
+
|
|
491
|
+
mesh_ui_colors = []
|
|
492
|
+
mesh_highlight_colors.each_with_index do |hl_hash, idx|
|
|
493
|
+
ui_hash = {
|
|
494
|
+
color_id: idx + 10,
|
|
495
|
+
fg: hl_hash[:fg],
|
|
496
|
+
bg: -1
|
|
497
|
+
}
|
|
498
|
+
Curses.init_pair(ui_hash[:color_id], ui_hash[:fg], ui_hash[:bg])
|
|
499
|
+
mesh_ui_colors.push(ui_hash)
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
red = mesh_ui_colors[0][:color_id]
|
|
503
|
+
green = mesh_ui_colors[1][:color_id]
|
|
504
|
+
yellow = mesh_ui_colors[2][:color_id]
|
|
505
|
+
blue = mesh_ui_colors[3][:color_id]
|
|
506
|
+
cyan = mesh_ui_colors[4][:color_id]
|
|
507
|
+
magenta = mesh_ui_colors[5][:color_id]
|
|
508
|
+
white = mesh_ui_colors[6][:color_id]
|
|
509
|
+
|
|
480
510
|
rx_height = Curses.lines - 4
|
|
481
511
|
rx_win = Curses::Window.new(rx_height, Curses.cols, 0, 0)
|
|
482
512
|
rx_win.scrollok(true)
|
|
483
513
|
rx_win.nodelay = true
|
|
484
|
-
rx_win.
|
|
485
|
-
|
|
514
|
+
rx_win.attron(Curses.color_pair(cyan) | Curses::A_BOLD)
|
|
515
|
+
|
|
516
|
+
# Make rx_header bold and green
|
|
517
|
+
rx_win.attron(Curses.color_pair(green) | Curses::A_BOLD)
|
|
518
|
+
rx_header = "<<< #{host}:#{port} | #{region}/#{topic} | ch:#{channel_num} >>>"
|
|
519
|
+
rx_header_len = rx_header.length
|
|
520
|
+
rx_header_pos = (Curses.cols / 2) - (rx_header_len / 2)
|
|
521
|
+
rx_win.setpos(1, rx_header_pos)
|
|
522
|
+
rx_win.addstr(rx_header)
|
|
523
|
+
rx_win.attroff(Curses.color_pair(green) | Curses::A_BOLD)
|
|
524
|
+
# Jump two lines below header before messages begin
|
|
525
|
+
rx_win.setpos(2, 1)
|
|
526
|
+
rx_win.attron(Curses.color_pair(cyan) | Curses::A_BOLD)
|
|
527
|
+
rx_header_bottom_line = "\u2014" * (Curses.cols - 2)
|
|
528
|
+
rx_header_bottom_line_pos = (Curses.cols / 2) - (rx_header_bottom_line.length / 2)
|
|
529
|
+
rx_win.addstr(rx_header_bottom_line)
|
|
530
|
+
rx_win.attroff(Curses.color_pair(cyan) | Curses::A_BOLD)
|
|
531
|
+
|
|
486
532
|
rx_win.refresh
|
|
487
533
|
|
|
488
534
|
tx_win = Curses::Window.new(4, Curses.cols, rx_height, 0)
|
|
489
535
|
tx_win.scrollok(false)
|
|
490
536
|
tx_win.nodelay = true
|
|
491
|
-
tx_win.box('|', "\u2500")
|
|
492
|
-
tx_win.addstr("TX Pane (echo while typing, last sent shown after Enter)\n")
|
|
493
537
|
tx_win.refresh
|
|
494
538
|
|
|
495
539
|
PWN.const_set(:MeshRxWin, rx_win)
|
|
@@ -498,24 +542,61 @@ module PWN
|
|
|
498
542
|
PWN.const_set(:MeshPi, pi)
|
|
499
543
|
|
|
500
544
|
# Live typing echo thread (idempotent)
|
|
501
|
-
tx_prompt = "#{region}/#{topic}
|
|
545
|
+
tx_prompt = "#{region}/#{topic} >>>"
|
|
502
546
|
echo_thread = Thread.new do
|
|
547
|
+
last_drawn = nil
|
|
503
548
|
loop do
|
|
504
549
|
break unless pi.config.pwn_mesh
|
|
505
550
|
|
|
506
551
|
tx_win = PWN.const_get(:MeshTxWin)
|
|
507
552
|
mutex = PWN.const_get(:MeshMutex)
|
|
508
553
|
msg_input = pi.input.line_buffer.to_s
|
|
509
|
-
ts = Time.now.strftime('%H:%M:%S')
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
554
|
+
ts = Time.now.strftime('%H:%M:%S%z')
|
|
555
|
+
cursor_pos = (Readline.respond_to?(:point) ? Readline.point : msg_input.length)
|
|
556
|
+
prefix = "[#{ts}] [TX] #{tx_prompt} "
|
|
557
|
+
base_line = "#{prefix}#{msg_input}"
|
|
558
|
+
cursor_abs_index = prefix.length + cursor_pos
|
|
559
|
+
current_line = base_line
|
|
560
|
+
if current_line != last_drawn
|
|
561
|
+
mutex.synchronize do
|
|
562
|
+
# Only show draft if after_read hook hasn't just written final TX (heuristic)
|
|
563
|
+
tx_win.clear
|
|
564
|
+
tx_win.attron(Curses.color_pair(red) | Curses::A_BOLD)
|
|
565
|
+
tx_header_bottom_line = "\u2014" * (Curses.cols - 2)
|
|
566
|
+
tx_header_bottom_line_pos = (Curses.cols / 2) - (rx_header_bottom_line.length / 2)
|
|
567
|
+
tx_win.addstr(rx_header_bottom_line)
|
|
568
|
+
tx_win.attroff(Curses.color_pair(red) | Curses::A_BOLD)
|
|
569
|
+
tx_win.attron(Curses.color_pair(yellow) | Curses::A_BOLD)
|
|
570
|
+
|
|
571
|
+
inner_width = Curses.cols - 2
|
|
572
|
+
segments = current_line.chars.each_slice(inner_width).map(&:join)
|
|
573
|
+
available_rows = tx_win.maxy - 2
|
|
574
|
+
segments.first(available_rows).each_with_index do |seg, idx|
|
|
575
|
+
tx_win.setpos(1 + idx, 1)
|
|
576
|
+
start_index = idx * inner_width
|
|
577
|
+
end_index = start_index + inner_width - 1
|
|
578
|
+
if cursor_abs_index.between?(start_index, end_index)
|
|
579
|
+
cursor_col = cursor_abs_index - start_index
|
|
580
|
+
(0..inner_width).each do |col|
|
|
581
|
+
ch = seg[col] || ' '
|
|
582
|
+
if col == cursor_col
|
|
583
|
+
tx_win.attron(Curses.color_pair(red) | Curses::A_REVERSE | Curses::A_BOLD)
|
|
584
|
+
tx_win.addch(ch)
|
|
585
|
+
tx_win.attroff(Curses.color_pair(red) | Curses::A_REVERSE | Curses::A_BOLD)
|
|
586
|
+
else
|
|
587
|
+
tx_win.addch(ch)
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
else
|
|
591
|
+
tx_win.addstr(seg.ljust(inner_width))
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
tx_win.attroff(Curses.color_pair(yellow) | Curses::A_BOLD)
|
|
595
|
+
tx_win.refresh
|
|
596
|
+
end
|
|
597
|
+
last_drawn = current_line
|
|
517
598
|
end
|
|
518
|
-
sleep 0.
|
|
599
|
+
sleep 0.005
|
|
519
600
|
end
|
|
520
601
|
end
|
|
521
602
|
echo_thread.abort_on_exception = false
|
|
@@ -545,22 +626,38 @@ module PWN
|
|
|
545
626
|
mutex = PWN.const_get(:MeshMutex)
|
|
546
627
|
|
|
547
628
|
from = packet[:node_id_from]
|
|
548
|
-
absolute_topic = "#{region}/#{topic.gsub('#', from)}
|
|
629
|
+
absolute_topic = "#{region}/#{topic.gsub('#', from)}"
|
|
549
630
|
to = packet[:node_id_to]
|
|
550
631
|
rx_text = decoded[:payload]
|
|
551
|
-
ts = Time.now.strftime('%H:%M:%S')
|
|
632
|
+
ts = Time.now.strftime('%H:%M:%S%z')
|
|
633
|
+
|
|
634
|
+
# Select a random color pair different from the last used one
|
|
635
|
+
colors_arr = PWN.const_get(:MeshColors)
|
|
636
|
+
last_pair = PWN.const_get(:MeshLastPair)
|
|
637
|
+
PWN.send(:remove_const, :MeshLastPair)
|
|
638
|
+
pair_choices = colors_arr.reject { |c| c == last_pair }
|
|
639
|
+
pair = pair_choices.sample
|
|
640
|
+
PWN.const_set(:MeshLastPair, pair)
|
|
641
|
+
rx_win.attron(Curses.color_pair(pair) | Curses::A_REVERSE)
|
|
642
|
+
|
|
643
|
+
current_line = "\n[#{ts}] [RX] #{absolute_topic} >>> #{rx_text}"
|
|
644
|
+
current_line = "\n[#{ts}] [RX][DM INTERCEPTED] #{absolute_topic} to: #{to} >>> #{rx_text}" unless to == '!ffffffff'
|
|
645
|
+
|
|
552
646
|
mutex.synchronize do
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
647
|
+
inner_width = Curses.cols - 2
|
|
648
|
+
content = current_line.sub(/\A\n/, '')
|
|
649
|
+
segments = content.scan(/.{1,#{inner_width}}/)
|
|
650
|
+
segments.each do |seg|
|
|
651
|
+
rx_win.addstr("\n")
|
|
652
|
+
rx_win.setpos(rx_win.cury, 1)
|
|
653
|
+
line = seg.ljust(inner_width)
|
|
654
|
+
rx_win.addstr(line)
|
|
557
655
|
end
|
|
558
|
-
# rx_win.addstr("#{msg.inspect}\n\n\n")
|
|
559
656
|
rx_win.refresh
|
|
560
657
|
end
|
|
658
|
+
rx_win.attroff(Curses.color_pair(pair) | Curses::A_REVERSE)
|
|
561
659
|
end
|
|
562
660
|
end
|
|
563
|
-
PWN.const_set(:MqttSubThread, true)
|
|
564
661
|
rescue StandardError => e
|
|
565
662
|
raise e
|
|
566
663
|
end
|
|
@@ -648,6 +745,8 @@ module PWN
|
|
|
648
745
|
PWN.const_get(:MeshTxWin).close
|
|
649
746
|
PWN.send(:remove_const, :MeshTxWin)
|
|
650
747
|
end
|
|
748
|
+
PWN.send(:remove_const, :MeshColors) if PWN.const_defined?(:MeshColors)
|
|
749
|
+
PWN.send(:remove_const, :MeshLastPair) if PWN.const_defined?(:MeshLastPair)
|
|
651
750
|
PWN.send(:remove_const, :MeshPi) if PWN.const_defined?(:MeshPi)
|
|
652
751
|
PWN.send(:remove_const, :MeshMutex) if PWN.const_defined?(:MeshMutex)
|
|
653
752
|
PWN.send(:remove_const, :MqttSubThread) if PWN.const_defined?(:MqttSubThread)
|
|
@@ -805,21 +904,6 @@ module PWN
|
|
|
805
904
|
text: tx_text,
|
|
806
905
|
psks: psks
|
|
807
906
|
)
|
|
808
|
-
|
|
809
|
-
# Update TX pane (bottom) with last sent message
|
|
810
|
-
if PWN.const_defined?(:MeshTxWin)
|
|
811
|
-
tx_win = PWN.const_get(:MeshTxWin)
|
|
812
|
-
mutex = PWN.const_get(:MeshMutex)
|
|
813
|
-
absolute_topic = "#{region}/#{topic.gsub('#', from)}:#{channel_num}"
|
|
814
|
-
ts = Time.now.strftime('%H:%M:%S')
|
|
815
|
-
mutex.synchronize do
|
|
816
|
-
tx_win.clear
|
|
817
|
-
tx_win.box('|', "\u2500")
|
|
818
|
-
tx_win.setpos(1, 1)
|
|
819
|
-
tx_win.addstr("[#{ts}] [TX] #{absolute_topic} >>> #{to}: #{tx_text}")
|
|
820
|
-
tx_win.refresh
|
|
821
|
-
end
|
|
822
|
-
end
|
|
823
907
|
end
|
|
824
908
|
end
|
|
825
909
|
rescue StandardError => e
|
data/lib/pwn/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pwn
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.481
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- 0day Inc.
|
|
@@ -519,14 +519,14 @@ dependencies:
|
|
|
519
519
|
requirements:
|
|
520
520
|
- - '='
|
|
521
521
|
- !ruby/object:Gem::Version
|
|
522
|
-
version: 2.
|
|
522
|
+
version: 2.9.0
|
|
523
523
|
type: :runtime
|
|
524
524
|
prerelease: false
|
|
525
525
|
version_requirements: !ruby/object:Gem::Requirement
|
|
526
526
|
requirements:
|
|
527
527
|
- - '='
|
|
528
528
|
- !ruby/object:Gem::Version
|
|
529
|
-
version: 2.
|
|
529
|
+
version: 2.9.0
|
|
530
530
|
- !ruby/object:Gem::Dependency
|
|
531
531
|
name: meshtastic
|
|
532
532
|
requirement: !ruby/object:Gem::Requirement
|