require 'xml/libxml' require 'iconv' require 'net/http' require 'uri' begin require 'net/https' $HAVE_SSL = true rescue $HAVE_SSL = false end $HAVE_SSL = false module GLSA Item = Struct.new :title, :synopsis, :affected, :access, :bugs def GLSA::get_url(url) # {{{ port = 80 use_ssl = false uri = URI.parse(url) port = uri.port if uri.port use_ssl = true if(uri.scheme.downcase == 'https') http = Net::HTTP.start(uri.host, port) http.use_ssl = use_ssl if $HAVE_SSL raise "Couldn't connect to host \"#{host}:#{port}\"" unless http resp, ret = nil, '' path = uri.path for i in 1..10 resp = http.get(path) case when Net::HTTPSuccess then ret = resp.body break when Net::HTTPRedirection then path = resp['location'] else raise "Error while fetching data from #{url}: #{$!}" end end http.finish resp.body end # }}} class GentooGLSA attr_accessor :items def initialize(id) parse_glsa(id) end def parse_glsa(id) begin puts "Get ID #{id}" content = GLSA::get_url("http://www.gentoo.org/security/en/glsa/glsa-#{id}.xml?passthru=1") rescue raise "Couldn't get URL \"http://www.gentoo.org/security/en/glsa/glsa-#{id}.xml?passthru=1\": #$!." end @items = [] if(content =~ /^<\?xml/) prs = XML::Parser.new prs.string = iso2utf(content) doc = prs.parse e = doc.root h = Hash.new ['title', 'synopsis', 'access'].each { |val| h[val] = (t_e = e.find(val).to_a) ? fix_character_encoding(t_e.first.to_s) : '' } affected = Hash.new affected['pkgname'] = fix_character_encoding(e.find('affected/package').to_a.first['name'].to_s) affected['unaffected'] = fix_character_encoding(e.find('affected/package/unaffected').to_a.first.to_s) affected['vuln'] = fix_character_encoding(e.find('affected/package/vulnerable').to_a.first.to_s) bugs = Array.new e.find('bug').each { |e| bugs << e.to_a.first.to_s } @items << GLSA::Item.new(h['title'], h['synopsis'], affected, h['access'], bugs) end end def fix_character_encoding(element) icon = Iconv.new('ISO-8859-1','UTF-8') icon.iconv(element) end def iso2utf(val) icon = Iconv.new('UTF-8','ISO-8859-1') icon.iconv(val) end end end class GlsaPlugin < Plugin @@handlers = { "glsa" => "handle_glsa" } def listen(um) if(!um.address?) if(um.kind_of?(UserMessage)) string = um.message.dup while(string.sub!(/glsa (\d+?-\d+)|http:\/\/www\.gentoo\.org\/security\/en\/glsa\/glsa-(\d+?-\d+).xml/i, '')) id = $1 id = $2 if(!$1) handle_glsa(id.to_s, um.replyto) end end end end def privmsg(m) meth = self.method(@@handlers[m.plugin]) meth.call(m) if(@bot.auth.allow?(m.plugin, m.source, m.replyto)) end def help(plugin, topic='') end def handle_glsa(m, replyadr = '') if(m.kind_of?(String)) glsa = GLSA::GentooGLSA.new(m) glsaid = m else glsa = GLSA::GentooGLSA.new(m.params) glsaid = m.params replyadr = m.replyto end if(glsa.items.empty?) @bot.say replyadr, "No glsa found for: #{glsaid}" else glsa.items.each { |item| @bot.say replyadr, "GLSA #{glsaid}: #{item.title} (#{item.synopsis.strip.split("\n").join(' ').squeeze(' ')}); Affected: #{item.affected['pkgname']}; Vulnerable: < #{item.affected['vuln']}; Unaffected: >= #{item.affected['unaffected']}; Access: #{item.access}; Related Bugs: #{item.bugs.join(', ')}: http://www.gentoo.org/security/en/glsa/glsa-#{glsaid}.xml" } end end end plugin = GlsaPlugin.new plugin.register("glsa")