|
| 1 | +require 'openssl' |
| 2 | +require 'uri' |
| 3 | +require 'cgi' |
| 4 | + |
| 5 | +class Transloadit |
| 6 | + class SmartCDN |
| 7 | + # @param workspace [String] Workspace slug |
| 8 | + # @param template [String] Template slug or template ID |
| 9 | + # @param input [String] Input value that is provided as `${fields.input}` in the template |
| 10 | + # @param auth_key [String] Authentication key |
| 11 | + # @param auth_secret [String] Authentication secret |
| 12 | + # @param url_params [Hash] Additional parameters for the URL query string (optional) |
| 13 | + # @param expire_in_ms [Integer] Expiration time in milliseconds from now (optional) |
| 14 | + # @param expire_at_ms [Integer] Expiration time as Unix timestamp in milliseconds (optional) |
| 15 | + # @return [String] Signed Smart CDN URL |
| 16 | + def self.signed_url(workspace:, template:, input:, auth_key:, auth_secret:, url_params: {}, expire_in_ms: nil, expire_at_ms: nil) |
| 17 | + raise ArgumentError, 'workspace is required' if workspace.nil? || workspace.empty? |
| 18 | + raise ArgumentError, 'template is required' if template.nil? || template.empty? |
| 19 | + raise ArgumentError, 'input is required' if input.nil? |
| 20 | + |
| 21 | + workspace_slug = CGI.escape(workspace) |
| 22 | + template_slug = CGI.escape(template) |
| 23 | + input_field = CGI.escape(input) |
| 24 | + |
| 25 | + expire_at = if expire_at_ms |
| 26 | + expire_at_ms |
| 27 | + elsif expire_in_ms |
| 28 | + (Time.now.to_f * 1000).to_i + expire_in_ms |
| 29 | + else |
| 30 | + (Time.now.to_f * 1000).to_i + (1 * 60 * 60 * 1000) # 1 hour default |
| 31 | + end |
| 32 | + |
| 33 | + query_params = {} |
| 34 | + url_params.each do |key, value| |
| 35 | + next if value.nil? |
| 36 | + if value.is_a?(Array) |
| 37 | + value.each do |val| |
| 38 | + next if val.nil? |
| 39 | + (query_params[key.to_s] ||= []) << val.to_s |
| 40 | + end |
| 41 | + else |
| 42 | + query_params[key.to_s] = [value.to_s] |
| 43 | + end |
| 44 | + end |
| 45 | + |
| 46 | + query_params['auth_key'] = [auth_key] |
| 47 | + query_params['exp'] = [expire_at.to_s] |
| 48 | + |
| 49 | + # Sort parameters to ensure consistent ordering |
| 50 | + sorted_params = query_params.sort.map do |key, values| |
| 51 | + values.compact.map { |v| "#{CGI.escape(key)}=#{CGI.escape(v)}" } |
| 52 | + end.flatten.reject(&:empty?).join('&') |
| 53 | + |
| 54 | + string_to_sign = "#{workspace_slug}/#{template_slug}/#{input_field}?#{sorted_params}" |
| 55 | + |
| 56 | + signature = OpenSSL::HMAC.hexdigest('sha256', auth_secret, string_to_sign) |
| 57 | + |
| 58 | + final_params = "#{sorted_params}&sig=#{CGI.escape("sha256:#{signature}")}" |
| 59 | + "https://#{workspace_slug}.tlcdn.com/#{template_slug}/#{input_field}?#{final_params}" |
| 60 | + end |
| 61 | + end |
| 62 | +end |
0 commit comments