Skip to content

Instantly share code, notes, and snippets.

@kryptek
Forked from repocers/AkamaiToken
Created October 29, 2013 21:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kryptek/7223209 to your computer and use it in GitHub Desktop.
Save kryptek/7223209 to your computer and use it in GitHub Desktop.
require "cgi"
class AkamaiTokenConfig
attr_accessor :window, :session_id, :data, :salt, :field_delimiter, :early_url_encoding, :ip
attr_reader :start_time, :hash_strategy, :acl, :url
def initialize(config={})
@ip = ''
self.start_time = Time.now.to_i
self.acl = '/*'
self.url = ''
self.hash_strategy = :sha256
self.key = '47187B5BA02AC633DC26A87B24927435'
@window = 140
@session_id = ''
@data = ''
@salt = ''
@field_delimiter = "~"
@early_url_encoding = false
end
def encode(value)
@early_url_encoding ? CGI.escape(value) : value
end
def start_time=(value)
return if value.nil?
raise "start_time out of range" if value < 0 || value > 4294967295
@start_time = value
end
# hexlify and unhexlify, respectively
def key=(value)
@key = AkamaiToken.hexlify(value)
end
def key
AkamaiToken.unhexlify(@key)
end
def hash_strategy=(value)
raise "Invalid hash strategy" if ![:md5, :sha1, :sha256].include?(value)
@hash_strategy = value
end
def acl=(value)
return if value.nil?
raise "ACL and URL cannot both be set at the same time" if !@url.nil?
@acl = value
end
def url=(value)
return if value.nil?
raise "ACL and URL cannot both be set at the same time" if !@acl.nil?
@url = value
end
def start_time_field
fieldify("st", @start_time)
end
def expiration_field
time = @start_time || Time.now.to_i
expiration = time + @window
fieldify("exp", expiration)
end
def acl_field
@url.nil? ? fieldify("acl", encode(@acl || "/*")) : ""
end
def url_field
@acl.nil? ? fieldify("url", encode(@url)) : ""
end
def ip_field
@ip ? fieldify("ip", encode(@ip)) : ""
end
def session_field
@session_id ? fieldify("id", encode(@session_id)) : ""
end
def data_field
@data ? fieldify("data", encode(@data)) : ""
end
def salt_field
@salt ? fieldify("salt", encode(@salt)) : ""
end
def fieldify(key, value)
"#{key}=#{value}"
end
end
class AkamaiToken
HASH_STRATEGY = { :sha1 => OpenSSL::Digest::SHA1, :sha256 => OpenSSL::Digest::SHA256,
:md5 => OpenSSL::Digest::MD5 }
def initialize(debug=false)
@debug = debug
end
def self.hexlify(value)
value.unpack("C*").map { |byte| "%02X" % byte }.join("")
end
def self.unhexlify(value)
[value].pack("H*")
end
def join_fields(fields, delimiter)
fields.reject { |field| field == "" }.join(delimiter)
end
def generate_token(token_config)
# sanity check
if (!token_config.acl && !token_config.url) || (token_config.acl && token_config.url)
raise "Must specify either an ACL or a URL but not both"
end
# determine values for hashing
t = token_config
mtoken = join_fields([t.ip_field, t.start_time_field, t.expiration_field, t.acl_field, t.session_field,
t.data_field], t.field_delimiter)
mtoken_digest = join_fields([mtoken, t.url_field, t.salt_field], t.field_delimiter)
encoded_key = AkamaiToken.hexlify(token_config.key)
hmac = OpenSSL::HMAC::digest(HASH_STRATEGY[token_config.hash_strategy].new, encoded_key, mtoken_digest)
encoded_hmac = AkamaiToken.hexlify(hmac)
if @debug
puts "SIGNING VALUE: #{mtoken_digest}"
puts "PRODUCES: #{encoded_hmac}"
end
"#{join_fields([mtoken, "hmac"], token_config.field_delimiter)}=#{encoded_hmac}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment