Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion lib/privy/public_api/privy_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

module Privy
class PrivyClient
# 15 minutes. Used when a caller doesn't pass `request_expiry:` and the
# client's PrivyRequestExpiryOptions doesn't override `default_ms`.
DEFAULT_REQUEST_EXPIRY_MS = 15 * 60 * 1_000

attr_reader :app_id, :app_secret

# @api private
Expand All @@ -10,6 +14,9 @@ class PrivyClient
# Service accessors.
attr_reader :wallets, :users, :policies, :key_quorums, :jwt_exchange

# @return [Privy::PrivyRequestExpiryOptions]
attr_reader :request_expiry_options

def initialize(
app_id: ENV["PRIVY_APP_ID"],
app_secret: ENV["PRIVY_APP_SECRET"],
Expand All @@ -18,10 +25,12 @@ def initialize(
max_retries: Privy::Client::DEFAULT_MAX_RETRIES,
timeout: Privy::Client::DEFAULT_TIMEOUT_IN_SECONDS,
initial_retry_delay: Privy::Client::DEFAULT_INITIAL_RETRY_DELAY,
max_retry_delay: Privy::Client::DEFAULT_MAX_RETRY_DELAY
max_retry_delay: Privy::Client::DEFAULT_MAX_RETRY_DELAY,
request_expiry: Privy::PrivyRequestExpiryOptions.build
)
@app_id = app_id
@app_secret = app_secret
@request_expiry_options = request_expiry

@api = Privy::Client.new(
app_id: app_id,
Expand All @@ -40,5 +49,23 @@ def initialize(
@key_quorums = Privy::Services::KeyQuorums.new(client: @api, privy_client: self)
@jwt_exchange = Privy::JwtExchangeService.new(wallets_resource: @api.wallets)
end

# Resolves the absolute Unix-ms timestamp to send as `privy-request-expiry`.
#
# Precedence:
# 1. Explicit per-call value (caller wins, even over `disabled: true`).
# 2. `disabled: true` -> nil (no header sent).
# 3. `request_expiry_options.default_ms` (offset from now).
# 4. {DEFAULT_REQUEST_EXPIRY_MS} (15 minutes from now).
#
# @param override_absolute_ms [Integer, nil] Absolute Unix-ms timestamp from caller.
# @return [Integer, nil]
def compute_request_expiry(override_absolute_ms = nil)
return override_absolute_ms unless override_absolute_ms.nil?
return nil if @request_expiry_options.disabled

Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond) +
(@request_expiry_options.default_ms || DEFAULT_REQUEST_EXPIRY_MS)
end
end
end
58 changes: 58 additions & 0 deletions test/privy/public_api/privy_client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,62 @@ def test_constructs_with_explicit_credentials
assert_equal("app-123", client.app_id)
assert_instance_of(Privy::Client, client.api)
end

def build_client(**opts)
Privy::PrivyClient.new(
app_id: "app-abc",
app_secret: "secret",
environment: :staging,
**opts
)
end

def now_ms
Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
end

def test_default_expiry_is_15_minutes_from_now
client = build_client
expiry = client.compute_request_expiry(nil)
assert_in_delta(now_ms + (15 * 60 * 1_000), expiry, 1_000)
end

def test_default_ms_overrides_hardcoded_default
client = build_client(
request_expiry: Privy::PrivyRequestExpiryOptions.build(default_ms: 60_000)
)
expiry = client.compute_request_expiry(nil)
assert_in_delta(now_ms + 60_000, expiry, 1_000)
end

def test_disabled_returns_nil
client = build_client(
request_expiry: Privy::PrivyRequestExpiryOptions.build(disabled: true)
)
assert_nil(client.compute_request_expiry(nil))
end

def test_explicit_override_wins_over_default_ms
client = build_client(
request_expiry: Privy::PrivyRequestExpiryOptions.build(default_ms: 60_000)
)
assert_equal(1_750_000_000_000, client.compute_request_expiry(1_750_000_000_000))
end

def test_explicit_override_wins_over_disabled
client = build_client(
request_expiry: Privy::PrivyRequestExpiryOptions.build(disabled: true)
)
assert_equal(1_750_000_000_000, client.compute_request_expiry(1_750_000_000_000))
end

def test_request_expiry_options_default_value_does_not_disable
client = build_client
refute_nil(client.compute_request_expiry(nil))
end

def test_compute_request_expiry_callable_without_arguments
client = build_client
refute_nil(client.compute_request_expiry)
end
end
Loading