Class: PatchFinder::Engine::MSU::Google

Inherits:
Object
  • Object
show all
Includes:
Helper
Defined in:
lib/patch_finder/engine/msu/google.rb

Constant Summary collapse

GOOGLEAPIS =
'https://www.googleapis.com'

Instance Attribute Summary collapse

Attributes included from Helper

#verbose

Instance Method Summary collapse

Methods included from Helper

#download_file, #download_files, #print_error, #print_line, #print_status, #print_verbose, #print_verbose_error, #read_file, #send_http_get_request

Constructor Details

#initialize(opts = {}) ⇒ Google

Initializes the Google API client.

Parameters:

  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :api_key (String)

    Google API key.

  • :search_engine_id (String)

    Google Search engine ID.



30
31
32
33
# File 'lib/patch_finder/engine/msu/google.rb', line 30

def initialize(opts = {})
  @api_key = opts[:api_key]
  @search_engine_id = opts[:search_engine_id]
end

Instance Attribute Details

#api_keyObject (readonly)

Returns the value of attribute api_key.



17
18
19
# File 'lib/patch_finder/engine/msu/google.rb', line 17

def api_key
  @api_key
end

#search_engine_idObject (readonly)

Returns the value of attribute search_engine_id.



18
19
20
# File 'lib/patch_finder/engine/msu/google.rb', line 18

def search_engine_id
  @search_engine_id
end

Instance Method Details

#find_msb_numbers(keyword) ⇒ Array

Returns the MSB (advisories) numbers for a search keyword.

Parameters:

  • keyword (String)

Returns:

  • (Array)


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/patch_finder/engine/msu/google.rb', line 39

def find_msb_numbers(keyword)
  msb_numbers = []
  next_starting_index = 1
  search_opts = {
    keyword: keyword,
    starting_index: next_starting_index
  }

  begin
    while
      results = search(search_opts)
      items = results['items']
      items.each do |item|
        title = item['title']
        msb = title.scan(/Microsoft Security Bulletin (MS\d\d\-\d\d\d)/).flatten.first
        msb_numbers << msb.downcase if msb
      end

      next_starting_index = get_next_index(results)
      next_page = results['queries']['nextPage']

      # Google API Documentation:
      # https://developers.google.com/custom-search/json-api/v1/using_rest
      # "This role is not present if the current results are the last page.
      # Note: This API returns up to the first 100 results only."
      break if next_page.nil? || next_starting_index > 100
    end
  rescue GoogleClientException => e
    print_verbose_error(e.message)
    return msb_numbers.uniq
  end

  msb_numbers.uniq
end

#get_next_index(j) ⇒ Fixnum

Returns startIndex

Parameters:

  • j (Hash)

    JSON response.

Returns:

  • (Fixnum)


134
135
136
# File 'lib/patch_finder/engine/msu/google.rb', line 134

def get_next_index(j)
  j['queries']['nextPage'] ? j['queries']['nextPage'].first['startIndex'] : 0
end

#get_total_results(j) ⇒ Fixnum

Returns totalResults

Parameters:

  • j (Hash)

    JSON response.

Returns:

  • (Fixnum)


126
127
128
# File 'lib/patch_finder/engine/msu/google.rb', line 126

def get_total_results(j)
  j['queries']['request'].first['totalResults'].to_i
end

#parse_results(res) ⇒ Object

Returns the string data to JSON.

Parameters:

  • res (Net::HTTPResponse)

Raises:



110
111
112
113
114
115
116
117
118
119
120
# File 'lib/patch_finder/engine/msu/google.rb', line 110

def parse_results(res)
  j = JSON.parse(res.body)

  if j['error']
    message = j['error']['errors'].first['message']
    reason  = j['error']['errors'].first['reason']
    fail GoogleClientException, "Google Search failed. #{message} (#{reason})"
  end

  j
end

#search(opts = {}) ⇒ Hash

Searches the Google API.

Parameters:

  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :starting_index (Fixnum)
  • :keyword (String)

Returns:

  • (Hash)

    JSON



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/patch_finder/engine/msu/google.rb', line 80

def search(opts = {})
  starting_index = opts[:starting_index]

  search_string = URI.escape([
    opts[:keyword],
    'intitle:"Microsoft Security Bulletin"',
    '-"Microsoft Security Bulletin Summary"'
  ].join(' '))

  req_str = "#{GOOGLEAPIS}/customsearch/v1?"
  req_str << "key=#{api_key}&"
  req_str << "cx=#{search_engine_id}&"
  req_str << "q=#{search_string}&"
  req_str << "start=#{starting_index.to_s}&"
  req_str << 'num=10&'
  req_str << 'c2coff=1'

  res = send_http_get_request(req_str)
  results = parse_results(res)
  if starting_index == 1
    print_verbose("Number of search results: #{get_total_results(results)}")
  end

  results
end