pwn 0.5.450 → 0.5.453

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.
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'diffy'
3
4
  require 'em/pure_ruby'
4
5
  require 'faye/websocket'
5
- # require 'openapi3_parser'
6
+ require 'nokogiri'
6
7
  require 'openssl'
7
8
  require 'rest-client'
8
9
  require 'securerandom'
10
+ require 'selenium/devtools/v140'
9
11
  require 'selenium/webdriver'
10
- require 'selenium/devtools'
11
12
  require 'socksify'
12
13
  require 'timeout'
13
14
  require 'watir'
@@ -336,14 +337,21 @@ module PWN
336
337
  chrome_types = %i[chrome headless_chrome]
337
338
  firefox_types = %i[firefox headless_firefox]
338
339
 
339
- # Future BiDi API that's more universally supported across browsers
340
- sleep 0.01 until browser_obj[:browser].driver.window_handles.any?
340
+ # Switch to the last opened window which should be the active tab
341
+ # if it doesn't work, try the first window handle. In chrome they
342
+ # get reversed sometimes ¯\_(ツ)_/¯
341
343
  target_window_handle = browser_obj[:browser].driver.window_handles.last
342
- browser_obj[:browser].driver.switch_to.window(target_window_handle)
344
+ begin
345
+ browser_obj[:browser].driver.switch_to.window(target_window_handle)
346
+
347
+ url = 'about:about'
348
+ url = 'chrome://chrome-urls' if chrome_types.include?(browser_type)
349
+ browser_obj[:browser].goto(url)
350
+ rescue Selenium::WebDriver::Error::WebDriverError
351
+ target_window_handle = browser_obj[:browser].driver.window_handles.first
352
+ retry
353
+ end
343
354
 
344
- url = 'about:about'
345
- url = 'chrome://chrome-urls/' if chrome_types.include?(browser_type)
346
- browser_obj[:browser].goto(url)
347
355
  rand_tab = SecureRandom.hex(8)
348
356
  browser_obj[:browser].execute_script("document.title = 'about:about-#{rand_tab}'")
349
357
 
@@ -467,6 +475,8 @@ module PWN
467
475
  case js
468
476
  when 'clear', 'clear;', 'clear()', 'clear();'
469
477
  script = 'console.clear()'
478
+ when 'debugger', 'debugger;', 'debugger()', 'debugger();'
479
+ script = 'debugger'
470
480
  else
471
481
  case return_to.to_s.downcase.to_sym
472
482
  when :stdout
@@ -931,205 +941,387 @@ module PWN
931
941
  end
932
942
 
933
943
  # Supported Method Parameters::
934
- # PWN::Plugins::TransparentBrowser.debugger(
935
- # browser_obj: 'required - browser_obj returned from #open method)',
936
- # action: 'optional - action to take :pause|:resume (Defaults to :pause)',
937
- # url: 'optional - URL to navigate to after pausing debugger (Defaults to nil)'
944
+ # current_dom = PWN::Plugins::TransparentBrowser.dom(
945
+ # browser_obj: 'required - browser_obj returned from #open method)'
938
946
  # )
939
947
 
940
- public_class_method def self.debugger(opts = {})
948
+ public_class_method def self.dom(opts = {})
941
949
  browser_obj = opts[:browser_obj]
942
- supported = %i[chrome headless_chrome]
943
- verified = verify_devtools_browser(browser_obj: browser_obj, supported: supported)
950
+ verified = verify_devtools_browser(browser_obj: browser_obj)
944
951
  puts 'This browser is not supported for DevTools operations.' unless verified
945
952
  return unless verified
946
953
 
947
- action = opts[:action] ||= :pause
948
- url = opts[:url]
949
-
950
- case action.to_s.downcase.to_sym
951
- when :pause
952
- browser_obj[:devtools].send_cmd(
953
- 'EventBreakpoints.setInstrumentationBreakpoint',
954
- eventName: 'scriptFirstStatement'
955
- )
956
- # browser_obj[:devtools].send_cmd('Debugger.enable')
957
- # browser_obj[:devtools].send_cmd(
958
- # 'Debugger.setInstrumentationBreakpoint',
959
- # instrumentation: 'beforeScriptExecution'
960
- # )
961
-
962
- # browser_obj[:devtools].send_cmd(
963
- # 'EventBreakpoints.setInstrumentationBreakpoint',
964
- # eventName: 'load'
965
- # )
966
-
967
- # browser_obj[:devtools].send_cmd(
968
- # 'Debugger.setPauseOnExceptions',
969
- # state: 'all'
970
- # )
954
+ dom_str = console(browser_obj: browser_obj, js: 'document.documentElement.outerHTML', return_to: :stdout)
955
+ raise 'DOM capture failed: returned nil or empty string. Check DevTools connection.' if dom_str.nil? || dom_str.strip.empty?
971
956
 
972
- begin
973
- Timeout.timeout(1) do
974
- browser_obj[:browser].refresh if url.nil?
975
- browser_obj[:browser].goto(url) unless url.nil?
976
- end
977
- rescue Timeout::Error
978
- url
979
- end
980
- when :resume
981
- browser_obj[:devtools].send_cmd(
982
- 'EventBreakpoints.removeInstrumentationBreakpoint',
983
- eventName: 'scriptFirstStatement'
984
- )
985
- browser_obj[:devtools].send_cmd('Debugger.resume')
986
- else
987
- raise 'ERROR: action parameter must be :pause or :resume'
988
- end
957
+ Nokogiri::HTML.parse(dom_str)
989
958
  rescue StandardError => e
990
959
  raise e
991
960
  end
992
961
 
993
962
  # Supported Method Parameters::
994
- # current_dom = PWN::Plugins::TransparentBrowser.dom(
963
+ # page_state = PWN::Plugins::TransparentBrowser.get_page_state(
995
964
  # browser_obj: 'required - browser_obj returned from #open method)'
996
965
  # )
997
966
 
998
- public_class_method def self.dom(opts = {})
967
+ public_class_method def self.get_page_state(opts = {})
999
968
  browser_obj = opts[:browser_obj]
1000
- supported = %i[chrome headless_chrome]
1001
- verified = verify_devtools_browser(browser_obj: browser_obj, supported: supported)
969
+ verified = verify_devtools_browser(browser_obj: browser_obj)
1002
970
  puts 'This browser is not supported for DevTools operations.' unless verified
1003
971
  return unless verified
1004
972
 
1005
- computed_styles = %i[display color font-size font-family]
1006
- browser_obj[:devtools].send_cmd(
1007
- 'DOMSnapshot.captureSnapshot',
1008
- computedStyles: computed_styles
1009
- ).transform_keys(&:to_sym)
1010
- rescue StandardError => e
1011
- raise e
1012
- end
973
+ js = <<~JS.strip
974
+ (function() {
975
+ try {
976
+ let ls = {};
977
+ for (let i = 0; i < localStorage.length; i++) {
978
+ let key = localStorage.key(i);
979
+ ls[key] = localStorage.getItem(key);
980
+ }
981
+ let ss = {};
982
+ for (let i = 0; i < sessionStorage.length; i++) {
983
+ let key = sessionStorage.key(i);
984
+ ss[key] = sessionStorage.getItem(key);
985
+ }
1013
986
 
1014
- # Supported Method Parameters::
1015
- # PWN::Plugins::TransparentBrowser.step_into(
1016
- # browser_obj: 'required - browser_obj returned from #open method)',
1017
- # steps: 'optional - number of steps taken (Defaults to 1)'
1018
- # )
987
+ let scripts = Array.from(document.scripts).map(s => ({
988
+ src: s.src,
989
+ innerHTML: s.innerHTML
990
+ })).filter(s => s.src || s.innerHTML);
1019
991
 
1020
- public_class_method def self.step_into(opts = {})
1021
- browser_obj = opts[:browser_obj]
1022
- supported = %i[chrome headless_chrome]
1023
- verified = verify_devtools_browser(browser_obj: browser_obj, supported: supported)
1024
- puts 'This browser is not supported for DevTools operations.' unless verified
1025
- return unless verified
992
+ let stylesheets = Array.from(document.querySelectorAll('link[rel="stylesheet"]')).map(l => l.href).filter(h => h);
1026
993
 
1027
- steps = opts[:steps].to_i
1028
- steps = 1 if steps.zero? || steps.negative?
994
+ let inline_styles = Array.from(document.querySelectorAll('style')).map(s => s.innerHTML).filter(c => c);
1029
995
 
1030
- diff_arr = []
1031
- steps.times do |s|
1032
- diff_hash = {}
1033
- step = s + 1
1034
- diff_hash[:step] = step
996
+ let forms = Array.from(document.forms).map(f => ({
997
+ action: f.action,
998
+ method: f.method,
999
+ elements: Array.from(f.elements).map(e => ({
1000
+ name: e.name,
1001
+ type: e.type,
1002
+ value: e.value
1003
+ }))
1004
+ }));
1035
1005
 
1036
- dom_before = dom(browser_obj: browser_obj)
1037
- diff_hash[:dom_before_step] = dom_before
1006
+ let iframes = Array.from(document.querySelectorAll('iframe')).map(i => i.src).filter(s => s);
1038
1007
 
1039
- browser_obj[:devtools].send_cmd('Debugger.stepInto')
1008
+ let csp_meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
1009
+ let csp = csp_meta ? csp_meta.content : null;
1040
1010
 
1041
- dom_after = dom(browser_obj: browser_obj)
1042
- diff_hash[:dom_after_step] = dom_after
1011
+ let feature_policy = [];
1012
+ if (document.featurePolicy) {
1013
+ feature_policy = document.featurePolicy.allowedFeatures().sort();
1014
+ }
1043
1015
 
1044
- da = dom_before.to_a - dom_after.to_a
1045
- diff_hash[:diff_dom] = da.to_h.transform_keys(&:to_sym)
1016
+ let is_framed = false;
1017
+ try {
1018
+ if (window.top !== window.self) {
1019
+ is_framed = true;
1020
+ }
1021
+ } catch (e) {
1022
+ is_framed = true;
1023
+ }
1046
1024
 
1047
- diff_arr.push(diff_hash)
1048
- end
1025
+ let resources = window.performance.getEntriesByType('resource').map(e => ({
1026
+ name: e.name,
1027
+ initiatorType: e.initiatorType
1028
+ }));
1029
+
1030
+ // Enhanced globals capture with values
1031
+ let globals = {};
1032
+ let propNames = Object.getOwnPropertyNames(window).sort();
1033
+ const safeStringify = (value, depth = 0) => {
1034
+ if (depth > 5) return '[Max depth exceeded]'; // Prevent deep recursion
1035
+ try {
1036
+ return JSON.stringify(value, (key, val) => {
1037
+ if (typeof val === 'function') {
1038
+ return val.toString(); // Capture function source
1039
+ } else if (typeof val === 'symbol') {
1040
+ return val.toString();
1041
+ } else if (val === window) {
1042
+ return '[Window reference]'; // Avoid circularity
1043
+ } else if (val && typeof val === 'object') {
1044
+ if (depth > 5) return '[Object (depth limit)]';
1045
+ return val; // Let JSON handle, recurse with depth
1046
+ }
1047
+ return val;
1048
+ });
1049
+ } catch (e) {
1050
+ return '[Stringify error: ' + e.message + ']';
1051
+ }
1052
+ };
1053
+
1054
+ for (let name of propNames) {
1055
+ try {
1056
+ let value = window[name];
1057
+ globals[name] = safeStringify(value);
1058
+ } catch (e) {
1059
+ globals[name] = '[Access error: ' + e.message + ']';
1060
+ }
1061
+ }
1049
1062
 
1050
- diff_arr
1063
+ return JSON.stringify({
1064
+ cookies: document.cookie,
1065
+ localStorage: ls,
1066
+ sessionStorage: ss,
1067
+ globals: globals, // Now an object with name: stringified_value
1068
+ scripts: scripts,
1069
+ stylesheets: stylesheets,
1070
+ inline_styles: inline_styles,
1071
+ stack: new Error().stack,
1072
+ location: {
1073
+ href: location.href,
1074
+ origin: location.origin,
1075
+ pathname: location.pathname,
1076
+ search: location.search,
1077
+ hash: location.hash
1078
+ },
1079
+ referrer: document.referrer,
1080
+ userAgent: navigator.userAgent,
1081
+ html_snapshot: document.documentElement.outerHTML,
1082
+ forms: forms,
1083
+ iframes: iframes,
1084
+ csp: csp,
1085
+ feature_policy: feature_policy,
1086
+ is_framed: is_framed,
1087
+ has_service_worker: 'serviceWorker' in navigator,
1088
+ resources: resources
1089
+ });
1090
+ } catch (e) {
1091
+ return JSON.stringify({
1092
+ error: e.message,
1093
+ stack: e.stack
1094
+ });
1095
+ }
1096
+ })()
1097
+ JS
1098
+
1099
+ browser_obj[:devtools].send_cmd('Console.clearMessages')
1100
+ browser_obj[:devtools].send_cmd('Log.clear')
1101
+ console_events = []
1102
+ browser_obj[:browser].driver.on_log_event(:console) { |event| console_events.push(event) }
1103
+
1104
+ # page_state = console(browser_obj: browser_obj, js: js, return_to: :stdout)
1105
+ console_cmd = { expression: js }
1106
+ runtime_resp = browser_obj[:devtools].send_cmd('Runtime.evaluate', **console_cmd)
1107
+ page_state = runtime_resp['result']['result']['value']
1108
+ JSON.parse(page_state, symbolize_names: true)
1109
+ rescue JSON::ParserError => e
1110
+ raise "Failed to parse state JSON: #{e.message}. Raw output: #{state_json.inspect}"
1051
1111
  rescue StandardError => e
1052
1112
  raise e
1053
1113
  end
1054
1114
 
1055
1115
  # Supported Method Parameters::
1056
- # PWN::Plugins::TransparentBrowser.step_out(
1057
- # browser_obj: 'required - browser_obj returned from #open method)',
1058
- # steps: 'optional - number of steps taken (Defaults to 1)'
1116
+ # messages = PWN::Plugins::TransparentBrowser.devtools_websocket_messages(
1117
+ # browser_obj: 'required - browser_obj returned from #open method)'
1059
1118
  # )
1060
1119
 
1061
- public_class_method def self.step_out(opts = {})
1120
+ public_class_method def self.devtools_websocket_messages(opts = {})
1062
1121
  browser_obj = opts[:browser_obj]
1063
- supported = %i[chrome headless_chrome]
1064
- verified = verify_devtools_browser(browser_obj: browser_obj, supported: supported)
1122
+ verified = verify_devtools_browser(browser_obj: browser_obj)
1065
1123
  puts 'This browser is not supported for DevTools operations.' unless verified
1066
1124
  return unless verified
1067
1125
 
1068
- steps = opts[:steps].to_i
1069
- steps = 1 if steps.zero? || steps.negative?
1070
-
1071
- diff_arr = []
1072
- steps.times do |s|
1073
- diff_hash = {}
1074
- step = s + 1
1075
- diff_hash[:step] = step
1126
+ devtools = browser_obj[:devtools]
1127
+ websocket = devtools.instance_variable_get(:@ws)
1128
+ websocket.instance_variable_get(:@messages)[nil]
1129
+ rescue StandardError => e
1130
+ raise e
1131
+ end
1076
1132
 
1077
- dom_before = dom(browser_obj: browser_obj)
1078
- diff_hash[:pre_step] = dom_before
1133
+ # Supported Method Parameters::
1134
+ # PWN::Plugins::TransparentBrowser.debugger(
1135
+ # browser_obj: 'required - browser_obj returned from #open method)',
1136
+ # action: 'optional - action to take :enable|:pause|:resume|:disable (Defaults to :enable)',
1137
+ # )
1079
1138
 
1080
- browser_obj[:devtools].send_cmd('Debugger.stepOut')
1139
+ public_class_method def self.debugger(opts = {})
1140
+ browser_obj = opts[:browser_obj]
1141
+ verified = verify_devtools_browser(browser_obj: browser_obj)
1142
+ puts 'This browser is not supported for DevTools operations.' unless verified
1143
+ return unless verified
1081
1144
 
1082
- dom_after = dom(browser_obj: browser_obj, step_sum: step_sum)
1083
- diff_hash[:post_step] = dom_after
1145
+ valid_actions = %i[enable pause resume disable]
1146
+ action = opts[:action] ||= :enable
1147
+ action = action.to_s.downcase.to_sym
1148
+ raise 'ERROR: action parameter must be :enable|:pause|:resume|:disable' unless valid_actions.include?(action)
1084
1149
 
1085
- da = dom_before.to_a - dom_after.to_a
1086
- diff_hash[:diff] = da.to_h.transform_keys(&:to_sym)
1150
+ devtools = browser_obj[:devtools]
1151
+ debugger_state = devtools.instance_variable_get(:@debugger_state)
1087
1152
 
1088
- diff_arr.push(diff_hash)
1153
+ case action
1154
+ when :enable
1155
+ if debugger_state.is_a?(Hash)
1156
+ debugger_state = devtools.instance_variable_get(:@debugger_state)
1157
+ devtools.remove_instance_variable(:@debugger_state) if debugger_state.is_a?(Hash)
1158
+ devtools.debugger.disable
1159
+ end
1160
+ debugger_state = {}
1161
+ breakpoint_arr = []
1162
+
1163
+ # breakpoint = devtools.debugger.set_instrumentation_breakpoint(instrumentation: 'beforeScriptExecution')
1164
+ bcmd = 'EventBreakpoints.setInstrumentationBreakpoint'
1165
+ event = 'load'
1166
+ breakpoint = devtools.send_cmd(bcmd, eventName: event)
1167
+ breakpoint['result']['breakpointId'] = "#{bcmd}.#{event}.#{SecureRandom.uuid}"
1168
+ breakpoint_arr.push(breakpoint)
1169
+ debugger_state[:breakpoints] = breakpoint_arr
1170
+
1171
+ devtools.runtime.disable
1172
+ devtools.log.disable
1173
+ devtools.network.disable
1174
+ devtools.page.disable
1175
+ devtools.debugger.enable
1176
+ when :pause
1177
+ devtools.debugger.pause
1178
+ Timeout.timeout(5) { browser_obj[:browser].refresh }
1179
+ when :resume
1180
+ devtools.debugger.resume
1181
+ when :disable
1182
+ debugger_state = devtools.instance_variable_get(:@debugger_state)
1183
+ devtools.remove_instance_variable(:@debugger_state) if debugger_state.is_a?(Hash)
1184
+ devtools.debugger.disable
1089
1185
  end
1090
1186
 
1091
- diff_arr
1187
+ devtools_websocket_messages = devtools_websocket_messages(browser_obj: browser_obj)
1188
+ debugger_state[:method] = devtools_websocket_messages['method']
1189
+ devtools.instance_variable_set(:@debugger_state, debugger_state)
1190
+ devtools
1191
+ rescue Timeout::Error
1192
+ devtools
1193
+ rescue Selenium::WebDriver::Error::WebDriverError => e
1194
+ puts e.message
1092
1195
  rescue StandardError => e
1093
1196
  raise e
1094
1197
  end
1095
1198
 
1096
1199
  # Supported Method Parameters::
1097
- # PWN::Plugins::TransparentBrowser.step_over(
1200
+ # page_state_arr = PWN::Plugins::TransparentBrowser.step(
1098
1201
  # browser_obj: 'required - browser_obj returned from #open method)',
1202
+ # action: 'optional - action to take :into|:out|:over (Defaults to :into)',
1099
1203
  # steps: 'optional - number of steps taken (Defaults to 1)'
1100
1204
  # )
1101
1205
 
1102
- public_class_method def self.step_over(opts = {})
1206
+ public_class_method def self.step(opts = {})
1103
1207
  browser_obj = opts[:browser_obj]
1104
1208
  supported = %i[chrome headless_chrome]
1105
1209
  verified = verify_devtools_browser(browser_obj: browser_obj, supported: supported)
1106
1210
  puts 'This browser is not supported for DevTools operations.' unless verified
1107
1211
  return unless verified
1108
1212
 
1213
+ valid_actions = %i[into out over]
1214
+ action = opts[:action] ||= :into
1215
+ action = action.to_s.downcase.to_sym
1216
+ raise 'ERROR: action parameter must be :into|:out|:over' unless valid_actions.include?(action)
1217
+
1109
1218
  steps = opts[:steps].to_i
1110
1219
  steps = 1 if steps.zero? || steps.negative?
1111
1220
 
1112
- diff_arr = []
1113
- steps.times do |s|
1114
- diff_hash = {}
1115
- step = s + 1
1116
- diff_hash[:step] = step
1221
+ devtools = browser_obj[:devtools]
1222
+ debugger_state = devtools.instance_variable_get(:@debugger_state)
1223
+ method = debugger_state[:method]
1224
+ if method != 'Debugger.paused'
1225
+ puts 'The debugger must be paused before stepping. Pausing now...'
1226
+ return devtools
1227
+ end
1117
1228
 
1118
- dom_before = dom(browser_obj: browser_obj)
1119
- diff_hash[:dom_before_step] = dom_before
1229
+ page_state_arr = []
1230
+ steps.times do |s|
1231
+ step_num = s + 1
1232
+ puts "Stepping #{action} (step #{step_num}/#{steps})..."
1233
+
1234
+ # before = get_page_state(browser_obj: browser_obj)
1235
+ # puts before.inspect
1236
+ before = devtools_websocket_messages(browser_obj: browser_obj)
1237
+ method = before['method']
1238
+ # puts before
1239
+ puts "\n"
1240
+
1241
+ if method == 'Debugger.paused'
1242
+ before_location = before['params']['callFrames'].first['location']
1243
+ start_location = before['params']['callFrames'].first['scopeChain'].first['startLocation']
1244
+ before_script_id = start_location['scriptId']
1245
+ from_line_num = start_location['lineNumber']
1246
+ from_column_num = start_location['columnNumber']
1247
+
1248
+ end_location = before['params']['callFrames'].first['scopeChain'].first['endLocation']
1249
+ to_line_num = end_location['lineNumber']
1250
+ to_column_num = end_location['columnNumber']
1251
+
1252
+ source_obj = devtools.debugger.get_script_source(script_id: before_script_id)
1253
+ source_code = source_obj['result']['scriptSource']
1254
+ # puts source_code
1255
+ # gets
1256
+
1257
+ source_lines = source_code.split("\n")
1258
+ source_lines_str = source_lines[from_line_num..to_line_num].join("\n")
1259
+ source_to_review = source_lines_str[from_column_num..to_column_num]
1260
+
1261
+ puts source_to_review
1262
+ request = source_lines_str[from_column_num..to_column_num]
1263
+ ai_analysis = PWN::AI::Introspection.reflect_on(request: request)
1264
+ puts "^^^ #{ai_analysis}" unless ai_analysis.nil?
1265
+ # gets
1266
+ end
1120
1267
 
1121
- browser_obj[:devtools].send_cmd('Debugger.stepOver')
1268
+ case action
1269
+ when :into
1270
+ devtools.debugger.step_into
1271
+ when :out
1272
+ devtools.debugger.step_out
1273
+ when :over
1274
+ devtools.debugger.step_over
1275
+ end
1122
1276
 
1123
- dom_after = dom(browser_obj: browser_obj, step_sum: step_sum)
1124
- diff_hash[:dom_after_step] = dom_after
1277
+ puts "\n" * 3
1278
+ after = devtools_websocket_messages(browser_obj: browser_obj)
1279
+ method = after['method']
1280
+ # puts after
1281
+ puts "\n"
1282
+
1283
+ if method == 'Debugger.paused'
1284
+ after_location = after['params']['callFrames'].first['scopeChain'].first['object']
1285
+ start_location = after['params']['callFrames'].first['scopeChain'].first['startLocation']
1286
+ after_script_id = start_location['scriptId']
1287
+ from_line_num = start_location['lineNumber']
1288
+ from_column_num = start_location['columnNumber']
1289
+
1290
+ end_location = after['params']['callFrames'].first['scopeChain'].first['endLocation']
1291
+ to_line_num = end_location['lineNumber']
1292
+ to_column_num = end_location['columnNumber']
1293
+
1294
+ source_obj = devtools.debugger.get_script_source(script_id: after_script_id)
1295
+ source_code = source_obj['result']['scriptSource']
1296
+ # puts source_code
1297
+ # gets
1298
+
1299
+ source_lines = source_code.split("\n")
1300
+ source_lines_str = source_lines[from_line_num..to_line_num].join("\n")
1301
+ source_to_review = source_lines_str[from_column_num..to_column_num]
1302
+
1303
+ puts source_to_review
1304
+ request = source_lines_str[from_column_num..to_column_num]
1305
+ ai_analysis = PWN::AI::Introspection.reflect_on(request: request)
1306
+ puts "^^^ #{ai_analysis}" unless ai_analysis.nil?
1307
+ # gets
1308
+ end
1309
+ puts "\n" * 6
1125
1310
 
1126
- da = dom_before.to_a - dom_after.to_a
1127
- diff_hash[:diff_dom] = da.to_h.transform_keys(&:to_sym)
1311
+ # step_hash = {
1312
+ # step: step_num,
1313
+ # action: action,
1314
+ # before: before,
1315
+ # after: after,
1316
+ # diff: diff.to_s(:text)
1317
+ # }
1128
1318
 
1129
- diff_arr.push(diff_hash)
1319
+ # page_state_arr.push(step_hash)
1130
1320
  end
1131
1321
 
1132
- diff_arr
1322
+ devtools
1323
+ rescue Selenium::WebDriver::Error::WebDriverError
1324
+ devtools
1133
1325
  rescue StandardError => e
1134
1326
  raise e
1135
1327
  end
@@ -1392,28 +1584,22 @@ module PWN
1392
1584
  keyword: 'optional - keyword in title or url used to close tabs (defaults to closing active tab)'
1393
1585
  )
1394
1586
 
1395
- #{self}.debugger(
1396
- browser_obj: 'required - browser_obj returned from #open method)',
1397
- action: 'optional - action to take :pause|:resume (Defaults to :pause)',
1398
- url: 'optional - URL to navigate to after pausing debugger (Defaults to nil)'
1399
- )
1400
-
1401
1587
  current_dom = #{self}.dom(
1402
1588
  browser_obj: 'required - browser_obj returned from #open method)'
1403
1589
  )
1404
1590
 
1405
- #{self}.step_into(
1406
- browser_obj: 'required - browser_obj returned from #open method)',
1407
- steps: 'optional - number of steps taken (Defaults to 1)'
1591
+ page_state = #{self}.get_page_state(
1592
+ browser_obj: 'required - browser_obj returned from #open method)'
1408
1593
  )
1409
1594
 
1410
- #{self}.step_out(
1595
+ #{self}.debugger(
1411
1596
  browser_obj: 'required - browser_obj returned from #open method)',
1412
- steps: 'optional - number of steps taken (Defaults to 1)'
1597
+ action: 'optional - action to take :enable|:pause|:resume|:disable (Defaults to :enable)'
1413
1598
  )
1414
1599
 
1415
- #{self}.step_over(
1600
+ #{self}.step(
1416
1601
  browser_obj: 'required - browser_obj returned from #open method)',
1602
+ action: 'optional - action to take :into|:out|:over (Defaults to :into)',
1417
1603
  steps: 'optional - number of steps taken (Defaults to 1)'
1418
1604
  )
1419
1605
 
@@ -22,61 +22,8 @@ module PWN
22
22
  report_name: HTMLEntities.new.encode(report_name.to_s.scrub.strip.chomp),
23
23
  data: []
24
24
  }
25
- report_name = opts[:report_name] ||= File.basename(Dir.pwd)
26
25
 
27
- # Calculate percentage of AI analysis based on the number of entries
28
- # total_entries = results_hash[:data].sum { |entry| entry[:line_no_and_contents].size }
29
- # puts "Total entries to analyze: #{total_entries}" if engine
30
-
31
- # percent_complete = 0.0
32
- # entry_count = 0
33
- # spin = TTY::Spinner.new(
34
- # '[:spinner] Report Generation Progress: :percent_complete :entry_count of :total_entries',
35
- # format: :dots,
36
- # hide_cursor: true
37
- # )
38
- # spin.auto_spin
39
-
40
- # ai_instrospection = PWN::Env[:ai][:introspection]
41
- # puts "Analyzing source code using AI engine: #{engine}\nModel: #{model}\nSystem Role Content: #{system_role_content}\nTemperature: #{temp}" if ai_instrospection
42
-
43
- # results_hash[:data].each do |hash_line|
44
- # git_repo_root_uri = hash_line[:filename][:git_repo_root_uri]
45
- # filename = hash_line[:filename][:entry]
46
- # hash_line[:line_no_and_contents].each do |src_detail|
47
- # entry_count += 1
48
- # percent_complete = (entry_count.to_f / total_entries * 100).round(2)
49
- # line_no = src_detail[:line_no]
50
- # source_code_snippet = src_detail[:contents]
51
- # author = src_detail[:author].to_s.scrub.chomp.strip
52
- # response = nil
53
- # if ai_instrospection
54
- # request = {
55
- # scm_uri: "#{git_repo_root_uri}/#{filename}",
56
- # line: line_no,
57
- # source_code_snippet: source_code_snippet
58
- # }.to_json
59
- # response = PWN::AI::Introspection.reflect(request: request)
60
- # end
61
- # ai_analysis = nil
62
- # if response.is_a?(Hash)
63
- # ai_analysis = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
64
- # ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
65
- # puts "AI Analysis Progress: #{percent_complete}% Line: #{line_no} | Author: #{author} | AI Analysis: #{ai_analysis}\n\n\n" if ai_analysis
66
- # end
67
- # src_detail[:ai_analysis] = ai_analysis.to_s.scrub.chomp.strip
68
- # spin.update(
69
- # percent_complete: "#{percent_complete}%",
70
- # entry_count: entry_count,
71
- # total_entries: total_entries
72
- # )
73
- # end
74
- # end
75
-
76
- # JSON object Completion
77
- # File.open("#{dir_path}/pwn_scan_git_source.json", 'w') do |f|
78
- # f.print(results_hash.to_json)
79
- # end
26
+ report_name = opts[:report_name] ||= File.basename(Dir.pwd)
80
27
  File.write(
81
28
  "#{dir_path}/#{report_name}.json",
82
29
  JSON.pretty_generate(results_hash)