Class: DmCloud::Signing
- Inherits:
-
Object
- Object
- DmCloud::Signing
- Defined in:
- lib/dm_cloud/signing.rb
Class Method Summary collapse
-
.build_digest_struct(base) ⇒ Object
Prepare datas for signing Params : base : contains media id and others for url signing.
-
.identify(request) ⇒ Object
Generate auth token for request from Media Params: request: A hash of params generated from Media methods and Media::MetaData Result : return a string which contain the auth token for the request <url>?auth=<expires>-<sec>-<nonce>-<md5sum>[-<pub-sec-data>].
-
.normalize(params) ⇒ Object
This block comes from Cloudkey gem.
-
.security(type = nil) ⇒ Object
The client must choose a security level for the signature.
- .security_data(type, value = nil) ⇒ Object
- .security_pub_sec_data(type, value) ⇒ Object
-
.sign(stream, security_datas = nil) ⇒ Object
To sign a URL, the client needs a secret shared with Dailymotion Cloud.
Class Method Details
.build_digest_struct(base) ⇒ Object
Prepare datas for signing Params :
base : contains media id and others for url signing
75 76 77 78 79 |
# File 'lib/dm_cloud/signing.rb', line 75 def self.build_digest_struct(base) result = [] base.each_pair { |key, value| result << value } result.join('') end |
.identify(request) ⇒ Object
Generate auth token for request from Media Params:
request: A hash of params generated from Media methods and Media::MetaData
Result :
return a string which contain the auth token for the request
<url>?auth=<expires>-<sec>-<nonce>-<md5sum>[-<pub-sec-data>]
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/dm_cloud/signing.rb', line 12 def self.identify(request) user_id = DmCloud.config[:user_key] api_key = DmCloud.config[:secret_key] #puts request normalized_request = normalize(request).to_s #puts 'identify:: normalized_values : ' + normalized_request + "\n" + '-' * 80 params = user_id + normalized_request + api_key #puts 'identify:: Values before MD5 encrypt : ' + params + "\n" + '-' * 80 checksum = Digest::MD5.hexdigest(params) auth_token = user_id + ':' + checksum auth_token end |
.normalize(params) ⇒ Object
This block comes from Cloudkey gem. I discovered this gem far after I start this one and I will try to add file upload from http or ftp. (Missing in their gem)
178 179 180 181 182 183 184 185 186 187 |
# File 'lib/dm_cloud/signing.rb', line 178 def self.normalize params case params when Array params.collect { |element| normalize(element) }.join('') when Hash params.to_a.sort_by {|a,b| a.to_s }.collect {|array| array.first.to_s + normalize(array.last)}.join('') else params.to_s end end |
.security(type = nil) ⇒ Object
The client must choose a security level for the signature. Security level defines the mechanism used by Dailymotion Cloud architecture to ensure the signed URL will be used by a single end-user. Params :
type :
None: The signed URL will be valid for everyone
ASNUM: The signed URL will only be valid for the AS of the end-user.
The ASNUM (for Autonomous System Number) stands for the network identification,
each ISP have a different ASNUM for instance.
IP: The signed URL will only be valid for the IP of the end-user.
This security level may wrongly block some users
which have their internet access load-balanced between several proxies.
This is the case in some office network or some ISPs.
User-Agent: Used in addition to one of the two former levels,
this level a limit on the exact user-agent of the end-user.
This is more secure but in some specific condition may lead to wrongly blocked users.
Use Once: The signed URL will only be usable once.
Note: should not be used with stream URLs.
Country: The URL can only be queried from specified countrie(s).
The rule can be reversed to allow all countries except some.
Referer: The URL can only be queried
if the Referer HTTP header contains a specified value.
If the URL contains a Referer header with a different value,
the request is refused. If the Referer header is missing,
the request is accepted in order to prevent from false positives as some browsers,
anti-virus or enterprise proxies may remove this header.
Delegate: This option instructs the signing algorithm
that security level information won’t be embeded into the signature
but gathered and lock at the first use.
Result :
Return a string which contain the signed url like
http://cdn.DmCloud.net/route/<user_id>/<media_id>/<asset_name>.<asset_extension>?auth=<auth_token>
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/dm_cloud/signing.rb', line 113 def self.security(type = nil) type = :none unless type type = type.to_sym if type.class == String case type when :none 0 # None when :delegate 1 << 0 # None when :asnum 1 << 1 # The number part of the end-user AS prefixed by the ‘AS’ string (ie: as=AS41690) when :ip 1 << 2 # The end-user quad dotted IP address (ie: ip=195.8.215.138) when :user_agent 1 << 3 # The end-user browser user-agent (parameter name is ua) when :use_once 1 << 4 # None when :country 1 << 5 # A list of 2 characters long country codes in lowercase by comas. If the list starts with a dash, the rule is inverted (ie: cc=fr,gb,de or cc=-fr,it). This data have to be stored in pub-sec-data component when :referer 1 << 6 # A list of URL prefixes separated by spaces stored in the pub-sec-data component (ex: rf=http;//domain.com/a/+http:/domain.com/b/). when :referer_strict 1 << 15 # Same as Referer (will deny direct access as well) end end |
.security_data(type, value = nil) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/dm_cloud/signing.rb', line 139 def self.security_data(type, value = nil) type = type.to_sym if type.class == String case type when :asnum "as=#{value}" # The number part of the end-user AS prefixed by the ‘AS’ string (ie: as=AS41690) when :ip "ip=#{value}" # The end-user quad dotted IP address (ie: ip=195.8.215.138) when :user_agent "ua=#{value}" # The end-user browser user-agent (parameter name is ua) when :country "cc=#{value}" # A list of 2 characters long country codes in lowercase by comas. If the list starts with a dash, the rule is inverted (ie: cc=fr,gb,de or cc=-fr,it). This data have to be stored in pub-sec-data component when :referer "rf=#{value}" # A list of URL prefixes separated by spaces stored in the pub-sec-data component (ex: rf=http;//domain.com/a/+http:/domain.com/b/). when :referer_strict "rf=#{value}" # A list of URL prefixes separated by spaces stored in the pub-sec-data component (ex: rf=http;//domain.com/a/+http:/domain.com/b/). else nil end end |
.security_pub_sec_data(type, value) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/dm_cloud/signing.rb', line 160 def self.security_pub_sec_data(type, value) type = type.to_sym if type.class == String case type when :country "cc=#{value}" # A list of 2 characters long country codes in lowercase by comas. If the list starts with a dash, the rule is inverted (ie: cc=fr,gb,de or cc=-fr,it). This data have to be stored in pub-sec-data component when :referer "rf=#{value}" # A list of URL prefixes separated by spaces stored in the pub-sec-data component (ex: rf=http;//domain.com/a/+http:/domain.com/b/). else nil end end |
.sign(stream, security_datas = nil) ⇒ Object
To sign a URL, the client needs a secret shared with Dailymotion Cloud. This secret is call client secret and is available in the back-office interface. Params:
expires: An expiration timestamp.
sec-level: A security level mask.
url-no-query: The URL without the query-string.
nonce: A 8 characters-long random alphanumeric lowercase string to make the signature unique.
secret: The client secret.
sec-data: If sec-level doesn’t have the DELEGATED bit activated,
this component contains concatenated informations
for all activated sec levels.
pub-sec-data: Some sec level data have to be passed in clear in the signature.
To generate this component the parameters are serialized using x-www-form-urlencoded, compressed with gzip and encoded in base64.
Result :
return a string which contain the signed url like
<expires>-<sec>-<nonce>-<md5sum>[-<pub-sec-data>]
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/dm_cloud/signing.rb', line 46 def self.sign(stream, security_datas = nil) raise StandardError, "missing :stream in params" unless stream sec_level = security(DmCloud.config[:security_level]) sec_data = security_data(DmCloud.config[:security_level], security_datas) unless security_datas.nil? base = { :sec_level => sec_level, :url_no_query => stream, :expires => (Time.now + 3.hours).to_i, # 3 hour from now :nonce => SecureRandom.hex(16)[0,16], :secret => DmCloud.config[:secret_key] } base.merge!(:sec_data => sec_data, :pub_sec_data => sec_data) unless sec_data.nil? digest_struct = build_digest_struct(base) check_sum = Digest::MD5.hexdigest(digest_struct) signed_url = [base[:expires], base[:sec_level], base[:nonce], check_sum].compact signed_url.merge!(:pub_sec_data => sec_data) unless sec_data.nil? # puts signed_url signed_url = signed_url.join('-') signed_url end |