Class: Zerobounce::BaseRequest

Inherits:
Object
  • Object
show all
Defined in:
lib/zerobounce/base_request.rb

Overview

Sends the HTTP request.

Direct Known Subclasses

MockRequest, Request

Class Method Summary collapse

Class Method Details

.__root_without_trailing_slashes__(root) ⇒ Object

Strips trailing slashes from root URL without using a regex (avoids ReDoS).



17
18
19
20
21
# File 'lib/zerobounce/base_request.rb', line 17

def self.__root_without_trailing_slashes__(root)
  s = root.to_s
  s = s.chomp('/') while s.end_with?('/')
  s
end

.__safe_file_path__(filepath) ⇒ Object

Resolves and validates filepath to prevent path traversal (e.g. ../../etc/passwd). Returns a canonical path only if the file is under the current directory and is a regular file.

Raises:

  • (ArgumentError)


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/zerobounce/base_request.rb', line 25

def self.__safe_file_path__(filepath)
  raise ArgumentError, 'File path is required' if filepath.nil? || filepath.to_s.empty?
  filepath = filepath.to_s
  expanded = File.expand_path(filepath)
  base = File.realpath(Dir.pwd)
  base_with_sep = base + File::SEPARATOR
  unless expanded == base || expanded.start_with?(base_with_sep)
    raise ArgumentError, 'File path must be under the current directory'
  end
  canonical = File.realpath(expanded)
  unless canonical == base || canonical.start_with?(base_with_sep)
    raise ArgumentError, 'File path must be under the current directory'
  end
  unless File.file?(canonical)
    raise ArgumentError, 'File path must point to a regular file'
  end
  canonical
end

._get(root, path, params, content_type = 'application/json') ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/zerobounce/base_request.rb', line 44

def self._get(root, path, params, content_type='application/json')

  # puts path
  # puts Zerobounce.config.apikey

  raise ("API key must be assigned") if not Zerobounce.config.apikey

  params[:api_key] = Zerobounce.config.apikey
  url = "#{Zerobounce::BaseRequest.__root_without_trailing_slashes__(root)}/#{path}"

  response = RestClient.get(url, {params: params})
  return response
end

._post(root, path, params, content_type = 'application/json', filepath = nil) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/zerobounce/base_request.rb', line 58

def self._post(root, path, params, content_type='application/json', filepath=nil)

  raise ("API key must be assigned") if not Zerobounce.config.apikey

  params[:api_key] = Zerobounce.config.apikey
  url = "#{Zerobounce::BaseRequest.__root_without_trailing_slashes__(root)}/#{path}"
  response = nil

  if filepath or content_type == 'multipart/form-data'
    params[:file] = File.new(Zerobounce::BaseRequest.__safe_file_path__(filepath), 'rb')
    params[:multipart] = true
    response = RestClient.post(url, params)

  elsif content_type == 'application/json'
    response = RestClient.post(url, params.to_json, \
                  content_type: :json, accept: :json)
  else
    # this shouldn't happen
    raise Error.new('Unknown content type specified in request.'\
      ' Must be either multipart/form-data or application/json.')
  end
  return response
end