Class: Ovh::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/ovh-client/client.rb,
lib/ovh-client/client/clock.rb,
lib/ovh-client/client/signature.rb

Overview

Signing wrapper over the generated Api transport gem. It builds an Ovh::Api::Client and wires request signing (and optional retries) onto its middleware seam, then exposes the generated surface through #api.

Examples:

ovh = Ovh::Client.new(application_key: 'ak', application_secret: 'as', consumer_key: 'ck')
ovh.api.me.get_me

Defined Under Namespace

Classes: Clock, Signature

Constant Summary collapse

ENDPOINTS =

OVH API endpoints per datacenter. Combined with the api_version to form base_url.

{
  eu: 'https://eu.api.ovh.com',
  ca: 'https://ca.api.ovh.com',
  us: 'https://api.us.ovhcloud.com'
}.freeze
RETRY_STATUSES =

HTTP statuses worth retrying: OVH rate limiting and transient gateway/server errors. Retries apply to idempotent verbs only (never POST/PATCH).

[429, 500, 502, 503, 504].freeze
RETRY_METHODS =
%i[get head delete put].freeze
REDACTED =
'[REDACTED]'
SENSITIVE_HEADERS =

Credential headers to scrub from any downstream logger. ovh-api's built-in logger runs before signing so it never sees these; these filters are for a caller-supplied logger placed after the signature middleware.

%w[X-Ovh-Application X-Ovh-Consumer X-Ovh-Signature].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(application_key:, application_secret:, consumer_key:, endpoint: :eu, api_version: '1.0', time_delta: 0, auto_sync_time: false, retries: 0, **options) ⇒ Client

rubocop:disable Metrics/MethodLength, Metrics/ParameterLists



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ovh-client/client.rb', line 68

def initialize(application_key:, application_secret:, consumer_key:,
               endpoint: :eu, api_version: '1.0',
               time_delta: 0, auto_sync_time: false, retries: 0, **options)
  @retries = retries
  base_url = "#{resolve_endpoint(endpoint)}/#{api_version}"
  # method(:synchronize_time!) is bound now but only invoked on the first signed
  # request, by which point @api is set.
  @clock = Clock.new(delta: time_delta, syncer: (auto_sync_time ? method(:synchronize_time!) : nil))
  @api = Ovh::Api::Client.new(base_url: base_url, **options) do |config|
    # Retry is registered before Signature so it wraps it: each retry attempt
    # re-enters Signature and re-signs with a fresh timestamp.
    config.use(Faraday::Retry::Middleware, retry_options) if retries.positive?
    config.use(Signature,
               application_key: application_key,
               application_secret: application_secret,
               consumer_key: consumer_key,
               clock: @clock)
  end
end

Instance Attribute Details

#apiOvh::Api::Client (readonly)

Returns the generated transport client.

Returns:

  • (Ovh::Api::Client)

    the generated transport client



33
34
35
# File 'lib/ovh-client/client.rb', line 33

def api
  @api
end

Class Method Details

.log_filtersArray<(Regexp, String)>

Regex/replacement pairs that scrub the OVH credential headers from a Faraday logger's output. Use when wiring your own logger downstream of signing.

Returns:

  • (Array<(Regexp, String)>)


38
39
40
41
42
# File 'lib/ovh-client/client.rb', line 38

def self.log_filters
  SENSITIVE_HEADERS.map do |header|
    [/(#{Regexp.escape(header)}:\s*)[^\r\n]+/i, "\\1#{REDACTED}"]
  end
end

.request_consumer_key(application_key:, access_rules:, endpoint: :eu, api_version: '1.0', redirection: nil) ⇒ Object

Start the OVH credential flow: request a consumer key scoped to the given access rules. Runs before a consumer key exists; needs only the application key (the call is unsigned, so application_secret is irrelevant here). The response carries a consumerKey and a validationUrl the end user must visit.

Parameters:

  • access_rules (Array<Hash>)

    e.g. [{ 'method' => 'GET', 'path' => '/*' }]

  • redirection (String, nil) (defaults to: nil)

    URL to redirect to after validation

Returns:

  • (Object)

    parsed JSON response (consumerKey, validationUrl, state)



59
60
61
62
63
64
65
# File 'lib/ovh-client/client.rb', line 59

def self.request_consumer_key(application_key:, access_rules:, endpoint: :eu, api_version: '1.0', redirection: nil)
  client = new(application_key: application_key, application_secret: nil, consumer_key: nil,
               endpoint: endpoint, api_version: api_version)
  body = { 'accessRules' => access_rules }
  body['redirection'] = redirection if redirection
  client.api.connection.call(:POST, '/auth/credential', body: body).data
end

Instance Method Details

#current_credentialObject

Fetch the credential currently in use (scope, status, expiration).

Returns:

  • (Object)

    parsed JSON response



103
104
105
# File 'lib/ovh-client/client.rb', line 103

def current_credential
  @api.connection.call(:GET, '/auth/currentCredential').data
end

#synchronize_time!Integer

Measure the offset between OVH's clock and the local one and remember it for every subsequent signed request. The call is unsigned (the /auth/time endpoint is public and skip-listed by Signature).

Returns:

  • (Integer)

    the computed offset, in seconds



94
95
96
97
98
99
# File 'lib/ovh-client/client.rb', line 94

def synchronize_time!
  server = @api.connection.call(:GET, '/auth/time').data
  delta  = server.to_i - Time.now.to_i
  @clock.synchronize!(delta)
  delta
end