module Apache::SecureDownload::Util

Constants

TIMESTAMP_LENGTH
TOKEN_KEY
TOKEN_LENGTH

Public Instance Methods

join(timestamp, token) click to toggle source

Joins timestamp and token parameters into a single value.

    # File lib/apache/secure_download/util.rb
114 def join(timestamp, token)
115   "#{"%0#{TIMESTAMP_LENGTH}x" % timestamp}#{token}"
116 end
real_path(path) click to toggle source

Returns path with timestamp and token parameter removed.

    # File lib/apache/secure_download/util.rb
129 def real_path(path)
130   clean(path, :path)
131 end
real_query(query) click to toggle source

Returns query with timestamp and token parameter removed.

    # File lib/apache/secure_download/util.rb
134 def real_query(query)
135   clean(query, :query)
136 end
secure_url(s, u, e = Time.now + 60) click to toggle source

Creates a valid URL to the secured resource, identified by url. The argument secret is the shared secret string that has been passed to the relevant RubyAccessHandler instance (cf. SecureDownload.new).

The expiration time may be either given as a Time (or Integer), or as a Hash with the following parameters:

:expires

Same as for the simple expires argument

:offset

The amount of seconds in the future (only if :expires is not given)

:cache

A time window for which identical URLs shall be produced, on average (defaults to :offset, if given)

Examples (s = "secret"):

# Only the path component (and an optional query component) will be taken into account
secure_url(s, "/secure/url")                    #=> "/secure/url?_asd=0047c3f5665671a9b3966e8bbed91fc0bb5594d576c504cdf0"
secure_url(s, "http://example.com/secure/url")  #=> "http://example.com/secure/url?_asd=0047c3f5665671a9b3966e8bbed91fc0bb5594d576c504cdf0"
secure_url(s, "/secure/url?query=value")        #=> "/secure/url?query=value&_asd=0047c3f566b482f943c35f4a1b5da6c646df6a65c0edc364cf"

# Expires in 10 minutes
secure_url(s, "/secure/url", Time.now + 600)  #=> "/secure/url?_asd=0047c3f7827e51f91cf4406f308a8df24f4e2cbf188de3c1bf"
secure_url(s, "/secure/url", :offset => 600)  #=> "/secure/url?_asd=0047c3fa9058eb12f9fc3fcd984fe4e918d3fd0590392c172d"

# Setting an offset will also allow caching; turn it off explicitly
secure_url(s, "/secure/url", :offset => 600, :cache => false)  #=> "/secure/url?_asd=0047c3f7827e51f91cf4406f308a8df24f4e2cbf188de3c1bf"

# Produce identical URLs for a window of 1 minute (on average)
t = Time.now
secure_url(s, "/secure/url", :expires => t,      :cache => 60)  #=> "/secure/url?_asd=0047c3f568ccf279daf1787d34ad063cbf5851ee88aae967fb"
secure_url(s, "/secure/url", :expires => t + 30, :cache => 60)  #=> "/secure/url?_asd=0047c3f568ccf279daf1787d34ad063cbf5851ee88aae967fb"
secure_url(s, "/secure/url", :expires => t + 60, :cache => 60)  #=> "/secure/url?_asd=0047c3f5a4c7dcea5679ad539a7bad1dc4b7f44eb3dd36d6e8"
secure_url(s, "/secure/url", :expires => t + 90, :cache => 60)  #=> "/secure/url?_asd=0047c3f5a4c7dcea5679ad539a7bad1dc4b7f44eb3dd36d6e8"

# Same as before, but use offset
secure_url(s, "/secure/url", :offset => 60) #=> "/secure/url?_asd=0047c3f5a4c7dcea5679ad539a7bad1dc4b7f44eb3dd36d6e8"
# 30 seconds later...
secure_url(s, "/secure/url", :offset => 60) #=> "/secure/url?_asd=0047c3f5a4c7dcea5679ad539a7bad1dc4b7f44eb3dd36d6e8"
# 30 seconds later...
secure_url(s, "/secure/url", :offset => 60) #=> "/secure/url?_asd=0047c3f5e0aa11618f1cc0883a29e9239b777ca53dfc4d9604"
# 30 seconds later...
secure_url(s, "/secure/url", :offset => 60) #=> "/secure/url?_asd=0047c3f5e0aa11618f1cc0883a29e9239b777ca53dfc4d9604"
    # File lib/apache/secure_download/util.rb
 92 def secure_url(s, u, e = Time.now + 60)
 93   if e.is_a?(Hash)
 94     e[:offset] ||= 60
 95     c = e[:cache] || e[:offset]
 96 
 97     t = (e[:expires] || Time.now + e[:offset]).to_i
 98 
 99     unless e[:cache] == false || c.zero?
100       # make the URL cacheable for +c+ seconds *on average*
101       t = ((t / c.to_f).round + 1) * c.to_i
102     end
103   else
104     t = e.to_i
105   end
106 
107   r, q = u[0, 1] == '/' ? u.split('?', 2) : URI.split(u).values_at(5, 7)
108   r << '?' << q if q
109 
110   u.sub(/#|\z/, "#{q ? '&' : '?'}#{TOKEN_KEY}=#{join(t, token(s, r, t))}\\&")
111 end
split(value) click to toggle source

Splits value into timestamp and token parameters.

    # File lib/apache/secure_download/util.rb
119 def split(value)
120   [value[0, TIMESTAMP_LENGTH].to_i(16), value[TIMESTAMP_LENGTH, TOKEN_LENGTH]]
121 end
token(secret, path, timestamp) click to toggle source

Computes the token from secret, path, and timestamp.

    # File lib/apache/secure_download/util.rb
124 def token(secret, path, timestamp)
125   Digest::SHA1.hexdigest("#{secret}#{real_path(path)}#{timestamp}")
126 end

Private Instance Methods

clean(string, type) click to toggle source

Returns string with timestamp and token parameter removed. The type indicates whether it’s a path or a query.

    # File lib/apache/secure_download/util.rb
142 def clean(string, type)
143   char = case type
144     when :path  then '\?'
145     when :query then '\A'
146     else raise ArgumentError, "type #{type.inspect} not supported"
147   end
148 
149   string.sub(/(#{char}|&)_asd=[^&]*(&?)/) { $1 unless $2.empty? }
150 end