|
| 1 | +#!/usr/bin/env ruby |
| 2 | +# -*- coding: binary -*- |
| 3 | + |
| 4 | +require 'optparse' |
| 5 | +require 'net/http' |
| 6 | +require 'uri' |
| 7 | +optparse = OptionParser.new do |opts| |
| 8 | + opts.banner = 'Usage: ruby tools/dev/update_user_agent_strings.rb [options]' |
| 9 | + opts.separator "This program updates lib/rex/user_agent.rb so Metasploit uses the most up-to-date User Agent strings across the framework." |
| 10 | + opts.separator "" |
| 11 | + opts.on('-h', '--help', 'Display this screen.') do |
| 12 | + puts opts |
| 13 | + exit |
| 14 | + end |
| 15 | +end |
| 16 | +optparse.parse! |
| 17 | + |
| 18 | +# colors and puts templates from msftidy.rb |
| 19 | + |
| 20 | +class String |
| 21 | + def red |
| 22 | + "\e[1;31;40m#{self}\e[0m" |
| 23 | + end |
| 24 | + |
| 25 | + def yellow |
| 26 | + "\e[1;33;40m#{self}\e[0m" |
| 27 | + end |
| 28 | + |
| 29 | + def green |
| 30 | + "\e[1;32;40m#{self}\e[0m" |
| 31 | + end |
| 32 | + |
| 33 | + def cyan |
| 34 | + "\e[1;36;40m#{self}\e[0m" |
| 35 | + end |
| 36 | +end |
| 37 | + |
| 38 | +# |
| 39 | +# Display an error message, given some text |
| 40 | +# |
| 41 | +def error(txt) |
| 42 | + puts "[#{'ERROR'.red}] #{cleanup_text(txt)}" |
| 43 | +end |
| 44 | + |
| 45 | +# |
| 46 | +# Display a warning message, given some text |
| 47 | +# |
| 48 | +def warning(txt) |
| 49 | + puts "[#{'WARNING'.yellow}] #{cleanup_text(txt)}" |
| 50 | +end |
| 51 | + |
| 52 | +# |
| 53 | +# Display a info message, given some text |
| 54 | +# |
| 55 | +def info(txt) |
| 56 | + puts "[#{'INFO'.cyan}] #{cleanup_text(txt)}" |
| 57 | +end |
| 58 | + |
| 59 | +def cleanup_text(txt) |
| 60 | + # remove line breaks |
| 61 | + txt = txt.gsub(/[\r\n]/, ' ') |
| 62 | + # replace multiple spaces by one space |
| 63 | + txt.gsub(/\s{2,}/, ' ') |
| 64 | +end |
| 65 | + |
| 66 | +def replace_agent_string(lines, replace_marker, url, regex) |
| 67 | + valid_chars = 'a-zA-Z0-9\(\);:\.,/_ ' |
| 68 | + regex = regex.gsub('{VALID_CHARS}', valid_chars) |
| 69 | + info "Checking: #{replace_marker}" |
| 70 | + |
| 71 | + index = lines.index { |line| line.include?(replace_marker) } |
| 72 | + raise "Couldn't find marker #{replace_marker}" if index.nil? |
| 73 | + |
| 74 | + uri = URI(url) |
| 75 | + response = Net::HTTP.get_response(uri) |
| 76 | + raise "Can't retrieve #{url}" unless response.is_a?(Net::HTTPSuccess) |
| 77 | + |
| 78 | + match = response.body.match(/#{regex}/) |
| 79 | + raise "Couldn't match regex #{regex}" if match.nil? |
| 80 | + |
| 81 | + new_string = match[1] |
| 82 | + |
| 83 | + old_line = lines[index] |
| 84 | + if old_line.include?("'#{new_string}'") |
| 85 | + puts " (Unchanged): #{new_string}" |
| 86 | + else |
| 87 | + new_line = old_line.gsub(/'(.*)'/, "'#{new_string}'") |
| 88 | + if old_line == new_line |
| 89 | + raise " Line didn't change: #{old_line}" |
| 90 | + end |
| 91 | + puts " New value is: #{new_string}" |
| 92 | + lines[index] = new_line |
| 93 | + end |
| 94 | +end |
| 95 | + |
| 96 | +chrome_url = "https://www.whatismybrowser.com/guides/the-latest-user-agent/chrome" |
| 97 | +edge_url = "https://www.whatismybrowser.com/guides/the-latest-user-agent/edge" |
| 98 | +safari_url = "https://www.whatismybrowser.com/guides/the-latest-user-agent/safari" |
| 99 | +firefox_url = "https://www.whatismybrowser.com/guides/the-latest-user-agent/firefox" |
| 100 | + |
| 101 | +user_agent_filename = 'lib/rex/user_agent.rb' |
| 102 | +lines = File.read(user_agent_filename).split("\n") |
| 103 | + |
| 104 | +replace_agent_string(lines, 'Chrome Windows', chrome_url, '<td>Chrome \\(Standard\\)</td>\s*<td>\s*<ul>\s*<li><span class="code">([{VALID_CHARS}]*Windows NT[{VALID_CHARS}]*)</span>') |
| 105 | +replace_agent_string(lines, 'Chrome MacOS', chrome_url, '<td>Chrome \\(Standard\\)</td>\s*<td>\s*<ul>\s*<li><span class="code">([{VALID_CHARS}]*Macintosh[{VALID_CHARS}]*)</span>') |
| 106 | +replace_agent_string(lines, 'Edge Windows', edge_url, '<td>Edge \\(Standard\\)</td>\s*<td>\s*<ul>\s*<li><span class="code">([{VALID_CHARS}]*Windows NT[{VALID_CHARS}]*)</span>') |
| 107 | +replace_agent_string(lines, 'Safari iPad', safari_url, '<td>\s*Safari on <b>Ipad</b>\s*</td>\s*<td>\s*<ul>\s*<li><span class="code">([{VALID_CHARS}]*iPad[{VALID_CHARS}]*)</span>') |
| 108 | +replace_agent_string(lines, 'Safari MacOS', safari_url, '<td>Safari \\(Standard\\)</td>\s*<td>\s*<ul>\s*<li><span class="code">([{VALID_CHARS}]*Macintosh[{VALID_CHARS}]*)</span>') |
| 109 | +replace_agent_string(lines, 'Firefox Windows', firefox_url, '<td>\s*Firefox on <b>Windows</b>\s*</td>\s*<td>\s*<ul>\s*<li><span class="code">([{VALID_CHARS}]*Windows NT[{VALID_CHARS}]*)</span>') |
| 110 | +replace_agent_string(lines, 'Firefox MacOS', firefox_url, '<td>\s*Firefox on <b>Macos</b>\s*</td>\s*<td>\s*<ul>\s*<li><span class="code">([{VALID_CHARS}]*Macintosh[{VALID_CHARS}]*)</span>') |
| 111 | + |
| 112 | +File.write(user_agent_filename, lines.join("\n") + "\n") |
0 commit comments