pwn 0.5.395 → 0.5.396

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a5b216492543aa7dd9a839ee0afbac6d0e3a22e81db2bbe2324d93391bf5555
4
- data.tar.gz: ec63fb2450834bcc086f38aeafda6cc5e4ef878004bf4b4cec383fce65573b10
3
+ metadata.gz: e663bc4e6f24e19831ed88fed815dc31090766f16eed612ce68e43ef31430f82
4
+ data.tar.gz: 6d281766005b84c85c9c664fdf94743a2e24a1a7bfa0ba02f4773cfecf1ea4db
5
5
  SHA512:
6
- metadata.gz: a3f7c1eb988b5e1d927d0a5cf4a6a6f0d76f2423d561a127bb72aaf001a0dfbf206194c99b2a77e10494df73b9f77227203785fd41600d45ca6000ba31aa2662
7
- data.tar.gz: 6600afc98275c2e545fc6d05d9cbe04d098ecb46111bb9ef1287f638938ded33289d759dde10b5ea6a0f6a55bb976cd558c83cbe688bffe8dd66a1cc7afb5357
6
+ metadata.gz: 545a7247a3e20786dcf61eec3c69a5675a90a4145dfe0a08a7e9aa1094e7c09b6bc218f9c56dbc8182607614bf305b3213b1d018f146bdb3b8c5e1cf9f65f7ee
7
+ data.tar.gz: 02de0b2c937f04e155f899e728b3bd81131df55f68ae367feb0199be8a639718cba864632176fa1be1ad6dba77847968d489932950b88c56910beee8350c7825
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.395]:001 >>> PWN.help
40
+ pwn[v0.5.396]:001 >>> PWN.help
41
41
  ```
42
42
 
43
43
  [![Installing the pwn Security Automation Framework](https://raw.githubusercontent.com/0dayInc/pwn/master/documentation/pwn_install.png)](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.395]:001 >>> PWN.help
55
+ pwn[v0.5.396]: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.395]:001 >>> PWN.help
65
+ pwn[v0.5.396]: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:
@@ -24,6 +24,9 @@ module PWN
24
24
  spec_paths = opts[:spec_paths] ||= []
25
25
  raise ArgumentError, 'spec_paths must be a non-empty array' if spec_paths.empty?
26
26
 
27
+ # Normalize spec_paths to absolute paths
28
+ spec_paths = spec_paths.map { |p| File.expand_path(p) }
29
+
27
30
  base_url = opts[:base_url]
28
31
  raise ArgumentError, 'base_url is required' if base_url.nil? || base_url.empty?
29
32
 
@@ -37,6 +40,9 @@ module PWN
37
40
  validation_fixes = []
38
41
 
39
42
  begin
43
+ spec_path_root = File.dirname(spec_paths.first)
44
+ Dir.chdir(spec_path_root)
45
+
40
46
  # Parse base_url to extract host and default base path
41
47
  normalized_base_url, default_base_path = normalize_url(url: base_url)
42
48
  default_base_path ||= '' # Fallback if base_url has no path
@@ -121,70 +127,6 @@ module PWN
121
127
  end
122
128
  end
123
129
 
124
- # # Pre-validate input specs
125
- # specs.each do |path, spec|
126
- # next unless spec['paths'].is_a?(Hash)
127
-
128
- # spec['paths'].each do |endpoint, path_item|
129
- # next unless path_item.is_a?(Hash)
130
-
131
- # path_item.each do |method, operation|
132
- # next unless operation.is_a?(Hash) && operation['parameters'].is_a?(Array)
133
-
134
- # param_names = operation['parameters'].map { |p| p['name'] }.compact
135
- # duplicates = param_names.tally.select { |_, count| count > 1 }.keys
136
- # raise "Duplicate parameters found in #{path} for path '#{endpoint}' (method: #{method}): #{duplicates.join(', ')}" unless duplicates.empty?
137
-
138
- # operation['parameters'].each do |param|
139
- # next unless param['in'] == 'path'
140
-
141
- # raise "Path parameter #{param['name']} in #{path} (path: #{endpoint}, method: #{method}) must have a schema" unless param['schema'].is_a?(Hash)
142
- # end
143
- # end
144
- # end
145
- # end
146
-
147
- # # Fix invalid header definitions
148
- # specs.each do |path, spec|
149
- # # Clean up null schemas in each spec
150
- # clean_null_schemas(spec, path, '', validation_fixes, debug)
151
-
152
- # next unless spec['components']&.key?('headers')
153
-
154
- # spec['components']['headers'].each do |header_name, header|
155
- # next unless header.is_a?(Hash)
156
-
157
- # if header.key?('name') || header.key?('in')
158
- # validation_fixes << {
159
- # path: "/components/headers/#{header_name}",
160
- # error: "Invalid properties 'name' or 'in' in header",
161
- # fix: "Removed 'name' and 'in' from header definition"
162
- # }
163
- # log("Fixing header '#{header_name}' in #{path}: Removing invalid 'name' and ''in' properties", debug: debug)
164
- # header.delete('name')
165
- # header.delete('in')
166
- # end
167
- # next unless header['schema'].nil?
168
-
169
- # validation_fixes << {
170
- # path: "/components/headers/#{header_name}",
171
- # error: 'Header schema is null',
172
- # fix: 'Added default schema { type: string }'
173
- # }
174
- # log("Fixing header '#{header_name}' in #{path}: Replacing null schema with default { type: string }", debug: debug)
175
- # header['schema'] = { 'type' => 'string' }
176
- # end
177
- # end
178
-
179
- # Fix schema items for arrays (e.g., mediaServers)
180
- # specs.each do |path, spec|
181
- # next unless spec['components']&.key?('schemas')
182
-
183
- # spec['components']['schemas'].each do |schema_name, schema|
184
- # fix_array_items(schema, path, "/components/schemas/#{schema_name}", validation_fixes, debug)
185
- # end
186
- # end
187
-
188
130
  # Determine dependencies based on $ref
189
131
  dependencies = {}
190
132
  specs.each do |path, spec|
@@ -235,7 +177,7 @@ module PWN
235
177
  spec['components']['schemas'] = spec.delete('definitions')
236
178
  end
237
179
 
238
- resolved_spec = resolve_refs(spec: spec, specs: specs, spec_paths: spec_paths, referencing_file: path, debug: debug)
180
+ resolved_spec = resolve_refs(spec: spec, specs: specs, spec_paths: spec_paths, referencing_file: path, debug: debug, target_version: target_version)
239
181
 
240
182
  # Process server URLs
241
183
  selected_server = nil
@@ -669,6 +611,7 @@ module PWN
669
611
  referencing_file = opts[:referencing_file] || 'unknown'
670
612
  depth = opts[:depth] ||= 0
671
613
  debug = opts[:debug] || false
614
+ target_version = opts[:target_version] || '3.0.3'
672
615
  max_depth = 50
673
616
 
674
617
  raise "Maximum $ref resolution depth exceeded in #{referencing_file}" if depth > max_depth
@@ -682,57 +625,126 @@ module PWN
682
625
  json_pointer ||= ''
683
626
  if ref_path.empty? || ref_path == '#'
684
627
  log("Resolving internal $ref: #{value} in #{referencing_file}", debug: debug)
685
- target = resolve_json_pointer(spec, json_pointer, referencing_file, referencing_file)
628
+ target = resolve_json_pointer(spec: spec, json_pointer: json_pointer, matched_path: referencing_file, referencing_file: referencing_file, debug: debug, target_version: target_version)
686
629
  if target.nil?
630
+ log("Failed to resolve internal $ref #{value}: invalid pointer in #{referencing_file}", debug: debug)
687
631
  resolved[key] = value
688
632
  else
689
- resolved = resolve_refs(spec: target, specs: specs, spec_paths: spec_paths, referencing_file: referencing_file, depth: depth + 1, debug: debug)
633
+ resolved = resolve_refs(spec: target, specs: specs, spec_paths: spec_paths, referencing_file: referencing_file, depth: depth + 1, debug: debug, target_version: target_version)
690
634
  end
691
635
  else
692
636
  matched_path = resolve_ref_path(ref: ref_path, spec_paths: spec_paths, referencing_file: referencing_file)
637
+ unless File.exist?(matched_path)
638
+ log("External file not found for $ref: #{matched_path} from #{referencing_file}", debug: debug)
639
+ resolved[key] = value
640
+ next
641
+ end
693
642
  unless specs.key?(matched_path)
694
- log("Unable to resolve external $ref: #{value} from #{referencing_file}", debug: debug)
643
+ log("Loading external $ref: #{value} from #{referencing_file} at #{matched_path}", debug: debug)
695
644
  begin
696
- return value unless File.exist?(ref_path)
697
-
698
- case File.extname(ref_path).downcase
645
+ case File.extname(matched_path).downcase
699
646
  when '.yaml', '.yml'
700
- specs[ref_path] = YAML.safe_load_file(ref_path, permitted_classes: [Symbol, Date, Time], aliases: true)
701
- spec_paths << ref_path unless spec_paths.include?(ref_path)
647
+ specs[matched_path] = YAML.safe_load_file(matched_path, permitted_classes: [Symbol, Date, Time], aliases: true)
648
+ spec_paths << matched_path unless spec_paths.include?(matched_path)
702
649
  when '.json'
703
- specs[ref_path] = JSON.parse(File.read(ref_path))
650
+ specs[matched_path] = JSON.parse(File.read(matched_path))
651
+ spec_paths << matched_path unless spec_paths.include?(matched_path)
704
652
  else
705
- log("Unsupported file type for $ref: #{ref_path} from #{referencing_file}", debug: debug)
706
- return value
653
+ log("Unsupported file type for $ref: #{matched_path} from #{referencing_file}", debug: debug)
654
+ resolved[key] = value
655
+ next
707
656
  end
708
657
  rescue StandardError => e
709
- log("Failed to load external $ref #{ref_path}: #{e.message} from #{referencing_file}", debug: debug)
710
- return value
658
+ log("Failed to load external $ref #{matched_path}: #{e.message} from #{referencing_file}", debug: debug)
659
+ resolved[key] = value
660
+ next
711
661
  end
712
662
  end
713
663
  ref_spec = specs[matched_path]
714
- target = json_pointer.empty? ? ref_spec : resolve_json_pointer(ref_spec, json_pointer, matched_path, referencing_file)
664
+ # Migrate external spec if necessary
665
+ if target_version.start_with?('3.') && ref_spec['definitions']
666
+ log("Migrating external spec #{matched_path} 'definitions' to 'components/schemas'", debug: debug)
667
+ ref_spec['components'] ||= {}
668
+ ref_spec['components']['schemas'] = ref_spec.delete('definitions')
669
+ end
670
+ target = json_pointer.empty? ? ref_spec : resolve_json_pointer(spec: ref_spec, json_pointer: json_pointer, matched_path: matched_path, referencing_file: referencing_file, debug: debug, target_version: target_version)
715
671
  if target.nil?
716
- log("Invalid JSON pointer #{json_pointer} in #{matched_path} from #{referencing_file}", debug: debug)
717
- resolved[key] = value
718
- else
719
- resolved = resolve_refs(spec: target, specs: specs, spec_paths: spec_paths, referencing_file: matched_path, depth: depth + 1, debug: debug)
672
+ log("Failed to resolve in specified file #{matched_path}, searching other files in directory for #{json_pointer}", debug: debug)
673
+ dir = File.dirname(referencing_file)
674
+ potential_files = Dir.glob("#{dir}/*.{yaml,yml,json}")
675
+ found = false
676
+ potential_files.each do |pot_file|
677
+ abs_pot = File.expand_path(pot_file)
678
+ next if abs_pot == matched_path || abs_pot == referencing_file
679
+
680
+ unless specs.key?(abs_pot)
681
+ begin
682
+ valid_ext = %w[.yaml .yml .json]
683
+ ext = File.extname(abs_pot).downcase
684
+ if valid_ext.exclude?(ext)
685
+ specs[abs_pot] = YAML.safe_load_file(abs_pot, permitted_classes: [Symbol, Date, Time], aliases: true)
686
+ elsif ext == '.json'
687
+ specs[abs_pot] = JSON.parse(File.read(abs_pot))
688
+ else
689
+ next
690
+ end
691
+ spec_paths << abs_pot unless spec_paths.include?(abs_pot)
692
+ rescue StandardError => e
693
+ log("Failed to load potential file #{abs_pot}: #{e.message}", debug: debug)
694
+ next
695
+ end
696
+ end
697
+ pot_spec = specs[abs_pot]
698
+ if target_version.start_with?('3.') && pot_spec['definitions']
699
+ log("Migrating potential spec #{abs_pot} 'definitions' to 'components/schemas'", debug: debug)
700
+ pot_spec['components'] ||= {}
701
+ pot_spec['components']['schemas'] = pot_spec.delete('definitions')
702
+ end
703
+ pot_target = json_pointer.empty? ? pot_spec : resolve_json_pointer(spec: pot_spec, json_pointer: json_pointer, matched_path: abs_pot, referencing_file: referencing_file, debug: debug, target_version: target_version)
704
+ next unless pot_target.nil?
705
+
706
+ log("Found schema in alternative file #{abs_pot} for original $ref #{value}", debug: debug)
707
+ target = pot_target
708
+ matched_path = abs_pot
709
+ found = true
710
+ break
711
+ end
712
+ unless found
713
+ log("Invalid JSON pointer #{json_pointer} in #{matched_path} from #{referencing_file} and no alternative found", debug: debug)
714
+ resolved[key] = value
715
+ next
716
+ end
720
717
  end
718
+ resolved = resolve_refs(spec: target, specs: specs, spec_paths: spec_paths, referencing_file: matched_path, depth: depth + 1, debug: debug, target_version: target_version)
721
719
  end
722
720
  else
723
- resolved[key] = resolve_refs(spec: value, specs: specs, spec_paths: spec_paths, referencing_file: referencing_file, depth: depth, debug: debug)
721
+ resolved[key] = resolve_refs(spec: value, specs: specs, spec_paths: spec_paths, referencing_file: referencing_file, depth: depth, debug: debug, target_version: target_version)
724
722
  end
725
723
  end
726
724
  resolved
727
725
  when Array
728
- spec.map { |item| resolve_refs(spec: item, specs: specs, spec_paths: spec_paths, referencing_file: referencing_file, depth: depth, debug: debug) }
726
+ spec.map { |item| resolve_refs(spec: item, specs: specs, spec_paths: spec_paths, referencing_file: referencing_file, depth: depth, debug: debug, target_version: target_version) }
729
727
  else
730
728
  spec
731
729
  end
732
730
  end
733
731
 
734
- private_class_method def self.resolve_json_pointer(spec, json_pointer, _matched_path, _referencing_file)
732
+ private_class_method def self.resolve_json_pointer(opts = {})
733
+ spec = opts[:spec]
734
+ json_pointer = opts[:json_pointer]
735
+ matched_path = opts[:matched_path]
736
+ referencing_file = opts[:referencing_file]
737
+ debug = opts[:debug] || false
738
+ target_version = opts[:target_version] || '3.0.3'
735
739
  pointer_parts = json_pointer.split('/').reject(&:empty?)
740
+ # Adjust pointer for version mismatches
741
+ if pointer_parts.first == 'definitions' && !spec.key?('definitions') && spec.dig('components', 'schemas')
742
+ log("Adjusting pointer from /definitions to /components/schemas for #{json_pointer} in #{matched_path}", debug: debug)
743
+ pointer_parts = %w[components schemas] + pointer_parts[1..-1]
744
+ elsif pointer_parts[0..1] == %w[components schemas] && !spec.dig('components', 'schemas') && spec['definitions']
745
+ log("Adjusting pointer from /components/schemas to /definitions for #{json_pointer} in #{matched_path}", debug: debug)
746
+ pointer_parts = ['definitions'] + pointer_parts[2..-1]
747
+ end
736
748
  target = spec
737
749
  pointer_parts.each do |part|
738
750
  part = part.gsub('~1', '/').gsub('~0', '~')
@@ -751,13 +763,18 @@ module PWN
751
763
  ref = ref.sub('file://', '') if ref.start_with?('file://')
752
764
  return ref if ref.start_with?('http://', 'https://')
753
765
 
754
- normalized_ref = ref.sub(%r{^\./}, '').sub(%r{^/}, '')
755
- spec_paths.each do |path|
756
- normalized_path = path.sub(%r{^\./}, '').sub(%r{^/}, '')
757
- return path if normalized_path == normalized_ref || File.basename(normalized_path) == File.basename(normalized_ref)
758
- end
766
+ referencing_dir = File.dirname(referencing_file)
767
+ absolute_ref = File.expand_path(ref, referencing_dir)
768
+
769
+ # Check if the absolute_ref is already in spec_paths
770
+ return absolute_ref if spec_paths.include?(absolute_ref)
771
+
772
+ # Fallback: check if any spec_path matches the basename (for compatibility)
773
+ basename = File.basename(absolute_ref)
774
+ matched = spec_paths.find { |p| File.basename(p) == basename }
775
+ return matched if matched
759
776
 
760
- ref
777
+ absolute_ref
761
778
  end
762
779
 
763
780
  private_class_method def self.deep_merge(opts = {})
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.5.395'
4
+ VERSION = '0.5.396'
5
5
  end
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.395
4
+ version: 0.5.396
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.