bqm 1.4.0 → 1.5.0

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/DOC.md +4 -0
  3. data/bin/bqm +37 -21
  4. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a7ea69f913278933cdcbae6a764b166d7990931ce1f68c1264f3c0127f548ad
4
- data.tar.gz: 65a2b6a2aa1e78864e48671a2f8b5e4ce395fa0eaead13ce3098806cc6391ce9
3
+ metadata.gz: 1a14c962fd0bf2a8c456bf7b9ff5416036289f61a8d4030ed246a77b6115aec0
4
+ data.tar.gz: d9d0bf051756b2eba968cdb37945fd953db2746b646f6a9888c4100207979792
5
5
  SHA512:
6
- metadata.gz: be95aaeccf71fb47aac6179e3be127d5d456fc88e4f67b1798b46dfafcf24cba0220cc6c5569fba98acbd24b9ca2f6bde71adb2604e9b0d9e2e4afeb56bb743f
7
- data.tar.gz: c752dc0e0d790b2b9e5337d5622cf05fd5d553558d7c3cb6654829ad54d8fb88157849e4d70c5a55589327c136dd2d442a857089d244923062953ba6b3a06f83
6
+ metadata.gz: 2283d7f843cfec5c8de3cf92044a12ed3731474125c6fa70675476cbce028b6dc26d8bdfd6ceafd8dd940d2a33a7d763558834a7ecbc709ab72b1ebcba18dc0c
7
+ data.tar.gz: 5f22350ef473520e98f26facab2a7a583b07739f0aa03b9d0fb312199a696e074ae311191476883af12bd46b1bf2413e4c519dd997a257d9ddca52e022ce4222
data/DOC.md ADDED
@@ -0,0 +1,4 @@
1
+ ## Options
2
+
3
+ - `-i`, `--local-sets`: if several items are provided, they must be comma (`,`) separated. Items can be either a Bloodhound custom query file, a bqm or a folder. In case of a bqm query sets file (similar to `query-sets.json`) or a folder, bqm will try to parse all JSON files inside it, so the folder should not contain other types of JSON files.
4
+ - `--ignore-default`: ignore the default `query-sets.json`. It's useful for **offline** usage or if you don't want the default data sets.
data/bin/bqm CHANGED
@@ -15,30 +15,40 @@ def find_dataset
15
15
  end
16
16
 
17
17
  # Merge remote sets defined in data/query-sets.json
18
- def merge_remote(source)
18
+ def merge_remote(source, verbose: false)
19
19
  sets = get_datasets(source)
20
20
  queries = []
21
21
  sets.each do |s|
22
22
  customqueries = Net::HTTP.get(URI(s))
23
23
  data = JSON.parse(customqueries)
24
24
  queries += data['queries']
25
+ puts " [*] File merged: #{s}" if verbose
25
26
  end
26
27
  queries
27
28
  end
28
29
 
29
30
  # Merge local sets provided by the user
30
- def merge_local(sources)
31
+ def merge_local(sources, verbose: false)
31
32
  queries = []
32
33
  sources.each do |source|
34
+ # If it's a file parse it
33
35
  if File.file?(source) && File.readable?(source)
34
- begin
35
- data = JSON.load_file(source)
36
- rescue NoMethodError # ruby 2.7 retro-compatibility
37
- data = JSON.parse(File.read(source))
36
+ data = json_load(source)
37
+ if data['queries']
38
+ queries += data['queries']
39
+ elsif data['sets']
40
+ queries += merge_remote(source, verbose: verbose)
41
+ else
42
+ raise KeyError, "The file #{source} is neiter a Bloodhound custom query file nor a bqm query sets file"
38
43
  end
39
- queries += data['queries']
44
+ puts " [*] File merged: #{source}" if verbose
45
+ # If it's a folder, retrieve all JSON files and assumes there are queries files
46
+ # Then recursive call for a normal file parsing
47
+ elsif File.directory?(source) && File.readable?(source)
48
+ qfiles = Dir.glob('*.json', base: source).map { |f| File.absolute_path(f, source) }
49
+ queries += merge_local(qfiles, verbose: verbose)
40
50
  else
41
- raise IOError, "The dataset file #{source} does not exist or is unreadable."
51
+ raise IOError, "The dataset file/directory #{source} does not exist or is unreadable."
42
52
  end
43
53
  end
44
54
  queries
@@ -78,13 +88,18 @@ def pretty_link(lst)
78
88
  end
79
89
 
80
90
  def get_datasets(source)
91
+ src = json_load(source)
92
+ src['sets']
93
+ end
94
+
95
+ def json_load(file)
81
96
  # ruby 3.0+
82
97
  begin
83
- src = JSON.load_file(source)
98
+ src = JSON.load_file(file)
84
99
  rescue NoMethodError # ruby 2.7 retro-compatibility
85
- src = JSON.parse(File.read(source))
100
+ src = JSON.parse(File.read(file))
86
101
  end
87
- src['sets']
102
+ src
88
103
  end
89
104
 
90
105
  if __FILE__ == $PROGRAM_NAME
@@ -92,19 +107,21 @@ if __FILE__ == $PROGRAM_NAME
92
107
 
93
108
  require 'optparse'
94
109
  options = {
95
- :'local-sets' => []
110
+ 'local-sets': []
96
111
  }
97
112
  OptionParser.new do |parser|
98
113
  parser.banner = 'Usage: bqm [options]'
99
114
 
100
115
  parser.on('-o', '--output-path PATH', 'Path where to store the query file')
101
116
  parser.on('-l', '--list', 'List available datasets')
102
- parser.on('-i', '--local-sets FILE,...', Array, 'Local custom queries files') do |f|
117
+ parser.on('-i', '--local-sets FILE,DIRECTORY,...', Array, 'Local custom queries files/directories') do |f|
103
118
  options[:'local-sets'] += f
104
119
  end
120
+ parser.on('--ignore-default', 'Ignore the default query-sets.json')
121
+ parser.on('-v', '--verbose', 'Display the name of the merged files/sets')
105
122
  parser.separator ''
106
123
  parser.separator 'Example: bqm -o ~/.config/bloodhound/customqueries.json'
107
- parser.separator 'Example: bqm -o /tmp/customqueries.json -i /tmp/a.json,/tmp/b.json'
124
+ parser.separator 'Example: bqm -o /tmp/customqueries.json -i /tmp/a.json,/home/user/folder'
108
125
  end.parse!(into: options)
109
126
 
110
127
  out = options[:'output-path']
@@ -120,20 +137,19 @@ if __FILE__ == $PROGRAM_NAME
120
137
  if File.file?(out) && File.readable?(out)
121
138
  puts "[+] The output path #{out} already exists"
122
139
  puts '[?] Do you want to overwrite it? [y/n]'
123
- if STDIN.gets.chomp == 'y'
140
+ if $stdin.gets.chomp == 'y'
124
141
  puts '[?] What to do with the existing queries? (merge / discard) [m/d]'
125
- flags[:merge_actual] = true if STDIN.gets.chomp == 'm'
142
+ flags[:merge_actual] = true if $stdin.gets.chomp == 'm'
126
143
  else
127
144
  exit
128
145
  end
129
146
  end
130
147
  puts '[+] Fetching and merging datasets'
131
- data = merge_remote(source)
148
+ data = []
149
+ data = merge_remote(source, verbose: options[:verbose]) unless options[:'ignore-default']
132
150
  local_set = options[:'local-sets']
133
- if local_set
134
- data += merge_local(local_set)
135
- end
136
- if flags[:'merge_actual']
151
+ data += merge_local(local_set, verbose: options[:verbose]) if local_set
152
+ if flags[:merge_actual]
137
153
  puts '[+] Merging your existing queries'
138
154
  data += JSON.parse(File.read(out))['queries']
139
155
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bqm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre ZANNI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-26 00:00:00.000000000 Z
11
+ date: 2023-06-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Deduplicate custom BloudHound queries from different datasets and merge
14
14
  them in one customqueries.json file.
@@ -18,6 +18,7 @@ executables:
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - DOC.md
21
22
  - LICENSE
22
23
  - bin/bqm
23
24
  - data/query-sets.json