Skip to content

Instantly share code, notes, and snippets.

@thisiscetin
Last active September 15, 2023 21:34
Show Gist options
  • Save thisiscetin/80b67b64c0742e5c5a410d13fcb341a7 to your computer and use it in GitHub Desktop.
Save thisiscetin/80b67b64c0742e5c5a410d13fcb341a7 to your computer and use it in GitHub Desktop.
Upcoach MD5 Request Validator for Rubyist
# frozen_string_literal: true
module UpcoachService
class RequestValidator < ApplicationService
def initialize(full_url, signing_secret)
@full_url = full_url
@signing_secret = signing_secret
end
def call
validate!
hash == signature
end
private
def hash
Digest::MD5.hexdigest("#{clean_url}::#{expires}::#{@signing_secret}")
end
def query_params
@query_params ||= Rack::Utils.parse_nested_query(
URI.parse(@full_url).query
)
end
def clean_url
@full_url
.split('&')
.map { |p| p.split('=') }
.filter { |sp| %w[signature expires].exclude?(sp.first) }
.map { |sp| sp.join('=') }
.join('&')
end
def signature
query_params['signature']
end
def expires
query_params['expires']
end
def validate!
raise ArgumentError, 'full_url can\'t be blank' if @full_url.blank?
raise ArgumentError, 'signing_secret can\'t be blank' if @signing_secret.blank?
raise ArgumentError, 'full_url is not valid' unless @full_url.match(
URI::DEFAULT_PARSER.make_regexp(%w[http https])
)
end
end
end
@thisiscetin
Copy link
Author

If you are not using Service Objects, you can implement a basic ApplicationService as below.

# frozen_string_literal: true

class ApplicationService
  def self.call(...)
    new(...).call
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment