path-packer-c/thing.rb

235 lines
5.2 KiB
Ruby
Raw Normal View History

2012-07-26 16:18:58 +00:00
#!/usr/bin/env ruby
require 'openssl'
require 'zlib'
require 'stringio'
require 'rubygems'
begin
require 'json'
rescue
abort('ERROR: plz2run #> gem install json')
end
# usage: ./content_from_pem.rb 5286016419950084643.pem
2012-07-26 20:04:52 +00:00
class Children
attr_accessor :children
def initialize()
@children = []
end
def each()
@children.each do |child|
yield child
end
end
def collect()
@children.each do |child|
yield child
end
end
def length()
@children.length
end
def [](i)
@children[i]
end
def []=(i, val)
@children[i] = val
end
def <<(other)
@children << other
end
def join(str)
@children.join(str)
end
end
2012-07-26 17:21:16 +00:00
class Node
2012-07-26 19:38:10 +00:00
attr_accessor :path, :children, :de_duped, :written
2012-07-26 17:21:16 +00:00
def initialize(path)
@path = path
2012-07-26 20:04:52 +00:00
@children = Children.new
2012-07-26 19:38:10 +00:00
@sig = nil
@de_duped = false
@written = false
2012-07-26 17:21:16 +00:00
end
def has_key?(key)
@children.each do |child|
if child.path == key
return true
end
end
return false
end
def get_child(name)
@children.each do |child|
if child.path == name
return child
end
end
return nil
end
2012-07-26 19:38:10 +00:00
def signature()
2012-07-26 20:04:52 +00:00
@sig = @path + "[" +
@children.collect { |x| x.signature }.join("|") + "]"
2012-07-26 19:38:10 +00:00
if @sig.nil?
@sig = @path + "[" +
@children.collect { |x| x.signature }.join("|") + "]"
end
@sig
end
def flatten()
flat = [self]
@children.each do |child|
flat += child.flatten
end
flat
end
2012-07-26 17:21:16 +00:00
def to_json(*a)
{
@path => @children
}.to_json(*a)
end
end
2012-07-26 16:18:58 +00:00
def akamai_hex_to_content_set(akamai_hex)
gzipped_hex = akamai_hex.gsub(":","").chomp("00")
gzipped_data = [gzipped_hex].pack("H*")
gzipped_data_io = StringIO.new(gzipped_data)
gz = Zlib::GzipReader.new(gzipped_data_io)
content_sets = gz.read.split("|")
begin
gz.close
rescue Zlib::GzipFile::NoFooter
end
return content_sets
end
2012-07-26 17:21:16 +00:00
def mk_hash(sgmts, parent)
2012-07-26 16:18:58 +00:00
segment = sgmts.shift
2012-07-26 17:21:16 +00:00
return parent if segment.nil?
unless parent.has_key?(segment)
parent.children << mk_hash(sgmts, Node.new(segment))
2012-07-26 16:18:58 +00:00
else
2012-07-26 17:21:16 +00:00
mk_hash(sgmts, parent.get_child(segment))
# else
# hash[segment].update(mk_hash(sgmts, hash[segment]))
2012-07-26 16:18:58 +00:00
end
2012-07-26 17:21:16 +00:00
return parent
2012-07-26 16:18:58 +00:00
end
2012-07-26 17:21:16 +00:00
def compress_prefix(parent)
parent.children.each do |child|
compress_prefix(child)
end
if parent.children.length == 1
2012-07-26 20:04:52 +00:00
puts "compressing #{parent.path} and #{parent.children[0].path}"
2012-07-26 17:21:16 +00:00
parent.path += "/" + parent.children[0].path
parent.children = parent.children[0].children
2012-07-26 16:18:58 +00:00
end
2012-07-26 17:21:16 +00:00
return parent
2012-07-26 16:18:58 +00:00
end
2012-07-26 19:38:10 +00:00
# given a tree of nodes, try and find branches that match the children of node.
# if found, replace those branches with node's children
def de_dupe(tree, node)
2012-07-26 20:04:52 +00:00
for i in 0..tree.children.length - 1
2012-07-26 19:38:10 +00:00
if tree.children[i] == node
# nothing
elsif node.signature == tree.children[i].signature
tree.children[i].de_duped = true
tree.children[i] = node
puts "Found dupe! " + node.signature
else
de_dupe(tree.children[i], node)
end
end
end
def de_dupe_driver(tree, nodes)
nodes.each do |node|
de_dupe(tree, node) unless node.de_duped
end
end
def binary_write(file, parent)
file.write(parent.path)
2012-07-26 20:04:52 +00:00
file.write("\0\0\0\0")
2012-07-26 19:38:10 +00:00
parent.children.each do |child|
# file.write(child.path)
2012-07-26 20:04:52 +00:00
file.write("\0\0\0")
2012-07-26 19:38:10 +00:00
end
parent.children.each do |child|
unless child.written
binary_write(file, child)
child.written = true
else
puts "not writing #{child.path}"
end
end
2012-07-26 16:56:45 +00:00
end
2012-07-26 16:18:58 +00:00
if $0 == __FILE__
if ARGV.length == 0
cert_data = STDIN.read
cert = OpenSSL::X509::Certificate.new(cert_data)
content_hex = cert.extensions.detect {|ext| ext.oid == 'subjectKeyIdentifier' }
abort('ERROR: no X509v3 extension for subjectKeyIdentifier') unless content_hex
2012-07-26 16:56:45 +00:00
puts akamai_hex_to_content_set(content_hex.value).join("|")
2012-07-26 16:18:58 +00:00
end
ARGV.each do |arg|
next unless FileTest.file?(arg)
cert_data = File.read(arg)
cert = OpenSSL::X509::Certificate.new(cert_data)
content_hex = cert.extensions.detect {|ext| ext.oid == 'subjectKeyIdentifier' }
abort('ERROR: no X509v3 extension for subjectKeyIdentifier') unless content_hex
ext = File.extname(arg)
txt_name = File.basename(arg, ext) + ".txt"
json_name = File.basename(arg, ext) + ".json"
2012-07-26 19:38:10 +00:00
binary = File.open(File.basename(arg, ext) + ".bin", "w")
2012-07-26 16:18:58 +00:00
sets = akamai_hex_to_content_set(content_hex.value)
File.open(txt_name, "w+") do |file|
file.write(sets)
end
File.open(json_name, "w+") do |file|
2012-07-26 17:21:16 +00:00
parent = Node.new("")
2012-07-26 16:18:58 +00:00
sets.each do |set|
line = set.start_with?("/") ? set[1..-1] : set
# => ["content", "beta", "rhel", "server", "6", "$releasever", "$basearch", "scalablefilesystem", "debug"]
chunks = line.split("/")
2012-07-26 17:21:16 +00:00
parent = mk_hash(chunks, parent)
2012-07-26 16:18:58 +00:00
end
2012-07-26 19:38:10 +00:00
# prime the signatures
de_dupe_driver(parent, parent.flatten)
parent = compress_prefix(parent)
2012-07-26 20:04:52 +00:00
de_dupe_driver(parent, parent.flatten)
2012-07-26 19:38:10 +00:00
binary_write(binary, parent)
2012-07-26 17:21:16 +00:00
file.write(parent.to_json)
2012-07-26 16:18:58 +00:00
end
puts "Wrote:\n [%d] %s\n [%d] %s" % [File.size(txt_name), txt_name, File.size(json_name), json_name]
end
end