|
| 1 | +module ApiAuth |
| 2 | + module RequestDrivers # :nodoc: |
| 3 | + # Internally, Faraday uses the class Faraday::Env to represent requests. The class is not meant |
| 4 | + # to be directly exposed to users, but this is what Faraday middlewares work with. See |
| 5 | + # <https://lostisland.github.io/faraday/middleware/>. |
| 6 | + class FaradayEnv |
| 7 | + include ApiAuth::Helpers |
| 8 | + |
| 9 | + def initialize(env) |
| 10 | + @env = env |
| 11 | + end |
| 12 | + |
| 13 | + def set_auth_header(header) |
| 14 | + @env.request_headers['Authorization'] = header |
| 15 | + @env |
| 16 | + end |
| 17 | + |
| 18 | + def calculated_hash |
| 19 | + sha256_base64digest(body) |
| 20 | + end |
| 21 | + |
| 22 | + def populate_content_hash |
| 23 | + return unless %w[POST PUT PATCH].include?(http_method) |
| 24 | + |
| 25 | + @env.request_headers['X-Authorization-Content-SHA256'] = calculated_hash |
| 26 | + end |
| 27 | + |
| 28 | + def content_hash_mismatch? |
| 29 | + if %w[POST PUT PATCH].include?(http_method) |
| 30 | + calculated_hash != content_hash |
| 31 | + else |
| 32 | + false |
| 33 | + end |
| 34 | + end |
| 35 | + |
| 36 | + def http_method |
| 37 | + @env.method.to_s.upcase |
| 38 | + end |
| 39 | + |
| 40 | + def content_type |
| 41 | + type = find_header(%w[CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE]) |
| 42 | + |
| 43 | + # When sending a body-less POST request, the Content-Type is set at the last minute by the |
| 44 | + # Net::HTTP adapter, which states in the documentation for Net::HTTP#post: |
| 45 | + # |
| 46 | + # > You should set Content-Type: header field for POST. If no Content-Type: field given, |
| 47 | + # > this method uses “application/x-www-form-urlencoded” by default. |
| 48 | + # |
| 49 | + # The same applies to PATCH and PUT. Hopefully the other HTTP adapters behave similarly. |
| 50 | + # |
| 51 | + type ||= 'application/x-www-form-urlencoded' if %w[POST PATCH PUT].include?(http_method) |
| 52 | + |
| 53 | + type |
| 54 | + end |
| 55 | + |
| 56 | + def content_hash |
| 57 | + find_header(%w[X-AUTHORIZATION-CONTENT-SHA256]) |
| 58 | + end |
| 59 | + |
| 60 | + def original_uri |
| 61 | + find_header(%w[X-ORIGINAL-URI X_ORIGINAL_URI HTTP_X_ORIGINAL_URI]) |
| 62 | + end |
| 63 | + |
| 64 | + def request_uri |
| 65 | + @env.url.request_uri |
| 66 | + end |
| 67 | + |
| 68 | + def set_date |
| 69 | + @env.request_headers['Date'] = Time.now.utc.httpdate |
| 70 | + end |
| 71 | + |
| 72 | + def timestamp |
| 73 | + find_header(%w[DATE HTTP_DATE]) |
| 74 | + end |
| 75 | + |
| 76 | + def authorization_header |
| 77 | + find_header(%w[Authorization AUTHORIZATION HTTP_AUTHORIZATION]) |
| 78 | + end |
| 79 | + |
| 80 | + def body |
| 81 | + body_source = @env.request_body |
| 82 | + if body_source.respond_to?(:read) |
| 83 | + result = body_source.read |
| 84 | + body_source.rewind |
| 85 | + result |
| 86 | + else |
| 87 | + body_source.to_s |
| 88 | + end |
| 89 | + end |
| 90 | + |
| 91 | + def fetch_headers |
| 92 | + capitalize_keys @env.request_headers |
| 93 | + end |
| 94 | + |
| 95 | + private |
| 96 | + |
| 97 | + def find_header(keys) |
| 98 | + keys.map { |key| @env.request_headers[key] }.compact.first |
| 99 | + end |
| 100 | + end |
| 101 | + end |
| 102 | +end |
0 commit comments