<commit_before>require 'time'
require 'uri'
require 'digest'

class Escher
  VERSION = '0.0.1'

  def canonicalize(method, url, body, date, headers, headers_to_sign = [])

    url, query = url.split '?', 2 # URI#parse cannot parse unicode characters in query string TODO use Adressable
    uri = URI.parse(url)

    ([
        method,
        canonicalize_path(uri),
        canonicalize_query(query),
    ] + canonicalize_headers(date, uri, headers) + [
        '',
        (headers_to_sign | %w(date host)).join(';'),
        request_body_hash(body)
    ]).join "\n"
  end

  # TODO: extract algo creation
  def get_string_to_sign(credential_scope, canonicalized_request, date, prefix, algo)
    date = long_date(date)
    lines = [
        algo_id(prefix, algo),
        date,
        date[0..7] + '/' + credential_scope,
        Digest::SHA256.new.hexdigest(canonicalized_request)
    ]
    lines.join "\n"
  end

  def long_date(date)
    Time.parse(date).utc.strftime("%Y%m%dT%H%M%SZ")
  end

  def algo_id(prefix, algo)
    prefix + '-HMAC-' + algo
  end

  def get_auth_header(header_name, vendor_prefix, algo, api_key_id, api_secret, date, credential_scope, method, url, body, headers, signed_headers)
    canonicalized_request = canonicalize method, url, body, date, headers, signed_headers
    string_to_sign = get_string_to_sign 'us-east-1/host/aws4_request', canonicalized_request, date, vendor_prefix, algo
    signing_key = calculate_signing_key(api_secret, date, vendor_prefix, credential_scope)

    signature = Digest::HMAC.hexdigest(string_to_sign, signing_key, Digest::SHA256)
    "#{algo_id(vendor_prefix, algo)} Credential=#{api_key_id}/#{long_date(date)[0..7]}/#{credential_scope}, SignedHeaders=#{signed_headers.uniq.join ';'}, Signature=#{signature}"
  end

  def calculate_signing_key(api_secret, date, vendor_prefix, credential_scope)
    signing_key = vendor_prefix + api_secret
    for data in [long_date(date)[0..7]] + credential_scope.split('/') do
      signing_key = Digest::HMAC.digest(data, signing_key, Digest::SHA256)
    end
    signing_key
  end

  def canonicalize_path(uri)
    path = uri.path
    while path.gsub!(%r{([^/]+)/\.\./?}) { |match|
      $1 == '..' ? match : ''
    } do
    end
      path = path.gsub(%r{/\./}, '/').sub(%r{/\.\z}, '/').gsub(/\/+/, '/')
    end

    def canonicalize_headers(date, uri, raw_headers)<commit_msg>[SUITEDEV-1992] fix hard coded credential scope<commit_after>require 'time'
require 'uri'
require 'digest'

class Escher
  VERSION = '0.0.1'

  def canonicalize(method, url, body, date, headers, headers_to_sign = [])

    url, query = url.split '?', 2 # URI#parse cannot parse unicode characters in query string TODO use Adressable
    uri = URI.parse(url)

    ([
        method,
        canonicalize_path(uri),
        canonicalize_query(query),
    ] + canonicalize_headers(date, uri, headers) + [
        '',
        (headers_to_sign | %w(date host)).join(';'),
        request_body_hash(body)
    ]).join "\n"
  end

  # TODO: extract algo creation
  def get_string_to_sign(credential_scope, canonicalized_request, date, prefix, algo)
    date = long_date(date)
    lines = [
        algo_id(prefix, algo),
        date,
        date[0..7] + '/' + credential_scope,
        Digest::SHA256.new.hexdigest(canonicalized_request)
    ]
    lines.join "\n"
  end

  def long_date(date)
    Time.parse(date).utc.strftime("%Y%m%dT%H%M%SZ")
  end

  def algo_id(prefix, algo)
    prefix + '-HMAC-' + algo
  end

  def get_auth_header(header_name, vendor_prefix, algo, api_key_id, api_secret, date, credential_scope, method, url, body, headers, signed_headers)
    canonicalized_request = canonicalize method, url, body, date, headers, signed_headers
    string_to_sign = get_string_to_sign credential_scope, canonicalized_request, date, vendor_prefix, algo
    signing_key = calculate_signing_key(api_secret, date, vendor_prefix, credential_scope)

    signature = Digest::HMAC.hexdigest(string_to_sign, signing_key, Digest::SHA256)
    "#{algo_id(vendor_prefix, algo)} Credential=#{api_key_id}/#{long_date(date)[0..7]}/#{credential_scope}, SignedHeaders=#{signed_headers.uniq.join ';'}, Signature=#{signature}"
  end

  def calculate_signing_key(api_secret, date, vendor_prefix, credential_scope)
    signing_key = vendor_prefix + api_secret
    for data in [long_date(date)[0..7]] + credential_scope.split('/') do
      signing_key = Digest::HMAC.digest(data, signing_key, Digest::SHA256)
    end
    signing_key
  end

  def canonicalize_path(uri)
    path = uri.path
    while path.gsub!(%r{([^/]+)/\.\./?}) { |match|
      $1 == '..' ? match : ''
    } do
    end
      path = path.gsub(%r{/\./}, '/').sub(%r{/\.\z}, '/').gsub(/\/+/, '/')
    end

    def canonicalize_headers(date, uri, raw_headers)
{'fraction_non_alphanumeric': 0.14446999790926196, 'fraction_numerical': 0.009617394940413967, 'mean_word_length': 3.6401551891367605, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3163525', 'n_tokens_mistral': 1698, 'n_tokens_neox': 1637, 'n_words': 334}