pwn 0.5.475 → 0.5.477
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/Gemfile +1 -0
- data/README.md +3 -3
- data/lib/pwn/plugins/jira_data_center.rb +32 -10
- data/lib/pwn/plugins/repl.rb +153 -14
- data/lib/pwn/version.rb +1 -1
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0883ae0b40d9110571980c47c111c805136ab3918abe2d521adfbea655fcce0f'
|
|
4
|
+
data.tar.gz: cfc639171b6d34083c3f6d82250d197586361014eaf5bc1c595aa870ca10c6e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b1f45ca0a0756512aa351dc0cc6a40ab5d53843cee7665034bb41141d7d15f7b41fb88bc39dbdc525a52893f23d47a9c1b13d8fcd27bcea6a391b7ff72a8b1ec
|
|
7
|
+
data.tar.gz: 0ad75d4a35ee90ba0c2cb788b0779990bdf484c98a2fdc27849c916b8f324daa91acf49cd9d9e90787f28aea60d7634b6ca78ea0bdb94582428630462db1e592
|
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.477]: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.477]: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.477]: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:
|
|
@@ -530,16 +530,38 @@ module PWN
|
|
|
530
530
|
end
|
|
531
531
|
end
|
|
532
532
|
|
|
533
|
-
#
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
533
|
+
# Attempt create, dynamically omit unlicensed fields on failure
|
|
534
|
+
attempt = 1
|
|
535
|
+
max_attempts = 5
|
|
536
|
+
cloned_issue = nil
|
|
537
|
+
begin
|
|
538
|
+
cloned_issue = create_issue(
|
|
539
|
+
project_key: project_key,
|
|
540
|
+
summary: summary,
|
|
541
|
+
issue_type: issue_type,
|
|
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
|
|
543
565
|
|
|
544
566
|
# Return the fully fetched cloned issue
|
|
545
567
|
get_issue(issue: cloned_issue[:key])
|
data/lib/pwn/plugins/repl.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'curses'
|
|
3
4
|
require 'fileutils'
|
|
4
5
|
require 'meshtastic'
|
|
5
6
|
require 'pry'
|
|
@@ -437,6 +438,14 @@ module PWN
|
|
|
437
438
|
pi.config.pwn_mesh = true
|
|
438
439
|
meshtastic_env = PWN::Env[:plugins][:meshtastic]
|
|
439
440
|
|
|
441
|
+
PWN.send(:remove_const, :MeshTxEchoThread) if PWN.const_defined?(:MeshTxEchoThread)
|
|
442
|
+
PWN.send(:remove_const, :MqttObj) if PWN.const_defined?(:MqttObj)
|
|
443
|
+
PWN.send(:remove_const, :MeshRxWin) if PWN.const_defined?(:MeshRxWin)
|
|
444
|
+
PWN.send(:remove_const, :MeshTxWin) if PWN.const_defined?(:MeshTxWin)
|
|
445
|
+
PWN.send(:remove_const, :MeshPi) if PWN.const_defined?(:MeshPi)
|
|
446
|
+
PWN.send(:remove_const, :MeshMutex) if PWN.const_defined?(:MeshMutex)
|
|
447
|
+
PWN.send(:remove_const, :MqttSubThread) if PWN.const_defined?(:MqttSubThread)
|
|
448
|
+
|
|
440
449
|
mqtt_env = meshtastic_env[:mqtt]
|
|
441
450
|
host = mqtt_env[:host]
|
|
442
451
|
port = mqtt_env[:port]
|
|
@@ -458,6 +467,100 @@ module PWN
|
|
|
458
467
|
psk = channel_env[:psk]
|
|
459
468
|
region = channel_env[:region]
|
|
460
469
|
topic = channel_env[:topic]
|
|
470
|
+
channel_num = channel_env[:channel_num]
|
|
471
|
+
|
|
472
|
+
# Init ncurses UI (idempotent) with separate RX (top) and TX (bottom) panes
|
|
473
|
+
Curses.init_screen
|
|
474
|
+
Curses.curs_set(0)
|
|
475
|
+
# Curses.crmode
|
|
476
|
+
# Curses.ESCDELAY = 0
|
|
477
|
+
Curses.start_color
|
|
478
|
+
Curses.use_default_colors
|
|
479
|
+
|
|
480
|
+
rx_height = Curses.lines - 4
|
|
481
|
+
rx_win = Curses::Window.new(rx_height, Curses.cols, 0, 0)
|
|
482
|
+
rx_win.scrollok(true)
|
|
483
|
+
rx_win.nodelay = true
|
|
484
|
+
rx_win.box('|', "\u2500")
|
|
485
|
+
rx_win.addstr("#{host}:#{port} >>> #{region}/#{topic}:#{channel_num} >>> Messages >>>\n")
|
|
486
|
+
rx_win.refresh
|
|
487
|
+
|
|
488
|
+
tx_win = Curses::Window.new(4, Curses.cols, rx_height, 0)
|
|
489
|
+
tx_win.scrollok(false)
|
|
490
|
+
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
|
+
tx_win.refresh
|
|
494
|
+
|
|
495
|
+
PWN.const_set(:MeshRxWin, rx_win)
|
|
496
|
+
PWN.const_set(:MeshTxWin, tx_win)
|
|
497
|
+
PWN.const_set(:MeshMutex, Mutex.new)
|
|
498
|
+
PWN.const_set(:MeshPi, pi)
|
|
499
|
+
|
|
500
|
+
# Live typing echo thread (idempotent)
|
|
501
|
+
tx_prompt = "#{region}/#{topic}:#{channel_num} >>> "
|
|
502
|
+
echo_thread = Thread.new do
|
|
503
|
+
loop do
|
|
504
|
+
break unless pi.config.pwn_mesh
|
|
505
|
+
|
|
506
|
+
tx_win = PWN.const_get(:MeshTxWin)
|
|
507
|
+
mutex = PWN.const_get(:MeshMutex)
|
|
508
|
+
msg_input = pi.input.line_buffer.to_s
|
|
509
|
+
ts = Time.now.strftime('%H:%M:%S')
|
|
510
|
+
mutex.synchronize do
|
|
511
|
+
# Only show draft if after_read hook hasn't just written final TX (heuristic)
|
|
512
|
+
tx_win.clear
|
|
513
|
+
tx_win.box('|', "\u2500")
|
|
514
|
+
tx_win.setpos(1, 1)
|
|
515
|
+
tx_win.addstr("[#{ts}] [TX] #{tx_prompt} #{msg_input}")
|
|
516
|
+
tx_win.refresh
|
|
517
|
+
end
|
|
518
|
+
sleep 0.01
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
echo_thread.abort_on_exception = false
|
|
522
|
+
PWN.const_set(:MeshTxEchoThread, echo_thread)
|
|
523
|
+
|
|
524
|
+
# Start single subscriber thread (idempotent)
|
|
525
|
+
psks = { active_channel => psk }
|
|
526
|
+
PWN::Plugins::ThreadPool.fill(
|
|
527
|
+
enumerable_array: [:mesh_sub],
|
|
528
|
+
max_threads: 1,
|
|
529
|
+
detach: true
|
|
530
|
+
) do |_|
|
|
531
|
+
Meshtastic::MQTT.subscribe(
|
|
532
|
+
mqtt_obj: mqtt_obj,
|
|
533
|
+
region: region,
|
|
534
|
+
topic: topic,
|
|
535
|
+
channel: channel_num,
|
|
536
|
+
psks: psks
|
|
537
|
+
) do |msg|
|
|
538
|
+
next unless msg.key?(:packet) && msg[:packet].key?(:decoded) && msg[:packet][:decoded].is_a?(Hash)
|
|
539
|
+
|
|
540
|
+
packet = msg[:packet]
|
|
541
|
+
decoded = packet[:decoded]
|
|
542
|
+
next unless decoded.key?(:portnum) && decoded[:portnum] == :TEXT_MESSAGE_APP
|
|
543
|
+
|
|
544
|
+
rx_win = PWN.const_get(:MeshRxWin)
|
|
545
|
+
mutex = PWN.const_get(:MeshMutex)
|
|
546
|
+
|
|
547
|
+
from = packet[:node_id_from]
|
|
548
|
+
absolute_topic = "#{region}/#{topic.gsub('#', from)}:#{channel_num}"
|
|
549
|
+
to = packet[:node_id_to]
|
|
550
|
+
rx_text = decoded[:payload]
|
|
551
|
+
ts = Time.now.strftime('%H:%M:%S')
|
|
552
|
+
mutex.synchronize do
|
|
553
|
+
if to == '!ffffffff'
|
|
554
|
+
rx_win.addstr("[#{ts}] [RX] #{absolute_topic}: #{rx_text}\n")
|
|
555
|
+
else
|
|
556
|
+
rx_win.addstr("[#{ts}] [RX][DM INTERCEPTED] #{absolute_topic} >>> #{to}: #{rx_text}\n")
|
|
557
|
+
end
|
|
558
|
+
# rx_win.addstr("#{msg.inspect}\n\n\n")
|
|
559
|
+
rx_win.refresh
|
|
560
|
+
end
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
PWN.const_set(:MqttSubThread, true)
|
|
461
564
|
rescue StandardError => e
|
|
462
565
|
raise e
|
|
463
566
|
end
|
|
@@ -523,8 +626,32 @@ module PWN
|
|
|
523
626
|
pi.config.pwn_ai_debug = false if pi.config.pwn_ai_debug
|
|
524
627
|
pi.config.pwn_ai_speak = false if pi.config.pwn_ai_speak
|
|
525
628
|
pi.config.completer = Pry::InputCompleter
|
|
526
|
-
|
|
527
|
-
|
|
629
|
+
return unless pi.config.pwn_mesh
|
|
630
|
+
|
|
631
|
+
pi.config.pwn_mesh = false
|
|
632
|
+
# Stop echo thread
|
|
633
|
+
if PWN.const_defined?(:MeshTxEchoThread)
|
|
634
|
+
PWN.const_get(:MeshTxEchoThread).kill
|
|
635
|
+
PWN.send(:remove_const, :MeshTxEchoThread)
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
if PWN.const_defined?(:MqttObj)
|
|
639
|
+
Meshtastic::MQTT.disconnect(mqtt_obj: PWN.const_get(:MqttObj))
|
|
640
|
+
PWN.send(:remove_const, :MqttObj)
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
if PWN.const_defined?(:MeshRxWin)
|
|
644
|
+
PWN.const_get(:MeshRxWin).close
|
|
645
|
+
PWN.send(:remove_const, :MeshRxWin)
|
|
646
|
+
end
|
|
647
|
+
if PWN.const_defined?(:MeshTxWin)
|
|
648
|
+
PWN.const_get(:MeshTxWin).close
|
|
649
|
+
PWN.send(:remove_const, :MeshTxWin)
|
|
650
|
+
end
|
|
651
|
+
PWN.send(:remove_const, :MeshPi) if PWN.const_defined?(:MeshPi)
|
|
652
|
+
PWN.send(:remove_const, :MeshMutex) if PWN.const_defined?(:MeshMutex)
|
|
653
|
+
PWN.send(:remove_const, :MqttSubThread) if PWN.const_defined?(:MqttSubThread)
|
|
654
|
+
Curses.close_screen
|
|
528
655
|
end
|
|
529
656
|
end
|
|
530
657
|
rescue StandardError => e
|
|
@@ -656,21 +783,18 @@ module PWN
|
|
|
656
783
|
psks = {}
|
|
657
784
|
psks[active_channel] = psk
|
|
658
785
|
|
|
659
|
-
|
|
786
|
+
tx_text = pi.input.line_buffer.to_s
|
|
660
787
|
to = '!ffffffff'
|
|
661
|
-
# If text include @! with 8 byte length
|
|
662
|
-
|
|
663
|
-
|
|
788
|
+
# If text include @! with 8 byte length,
|
|
789
|
+
# send DM to that address
|
|
790
|
+
if tx_text.include?('@!')
|
|
791
|
+
to_raw = tx_text.split('@').last.chomp[0..8]
|
|
664
792
|
# If to_raw[1..-1] is hex than set to = to_raw
|
|
665
793
|
to = to_raw if to_raw[1..-1].match?(/^[a-fA-F0-9]{8}$/)
|
|
666
|
-
|
|
794
|
+
# Remove any spaces from beginning of to_raw
|
|
795
|
+
tx_text.gsub!("@#{to_raw}", '').strip!
|
|
667
796
|
end
|
|
668
|
-
|
|
669
|
-
puts "To: #{to}"
|
|
670
|
-
puts "Region: #{region}"
|
|
671
|
-
puts "Topic: #{topic}"
|
|
672
|
-
puts "Channel #: #{channel_num}"
|
|
673
|
-
puts "Text: #{text}\n\n"
|
|
797
|
+
|
|
674
798
|
Meshtastic::MQTT.send_text(
|
|
675
799
|
mqtt_obj: mqtt_obj,
|
|
676
800
|
from: from,
|
|
@@ -678,9 +802,24 @@ module PWN
|
|
|
678
802
|
region: region,
|
|
679
803
|
topic: topic,
|
|
680
804
|
channel: channel_num,
|
|
681
|
-
text:
|
|
805
|
+
text: tx_text,
|
|
682
806
|
psks: psks
|
|
683
807
|
)
|
|
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
|
|
684
823
|
end
|
|
685
824
|
end
|
|
686
825
|
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.477
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- 0day Inc.
|
|
@@ -205,6 +205,20 @@ dependencies:
|
|
|
205
205
|
- - '='
|
|
206
206
|
- !ruby/object:Gem::Version
|
|
207
207
|
version: 7.0.0
|
|
208
|
+
- !ruby/object:Gem::Dependency
|
|
209
|
+
name: curses
|
|
210
|
+
requirement: !ruby/object:Gem::Requirement
|
|
211
|
+
requirements:
|
|
212
|
+
- - '='
|
|
213
|
+
- !ruby/object:Gem::Version
|
|
214
|
+
version: 1.5.3
|
|
215
|
+
type: :runtime
|
|
216
|
+
prerelease: false
|
|
217
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
218
|
+
requirements:
|
|
219
|
+
- - '='
|
|
220
|
+
- !ruby/object:Gem::Version
|
|
221
|
+
version: 1.5.3
|
|
208
222
|
- !ruby/object:Gem::Dependency
|
|
209
223
|
name: diffy
|
|
210
224
|
requirement: !ruby/object:Gem::Requirement
|