lib/ruby_conversations/aws_credential_provider.rb
# frozen_string_literal: true require 'aws-sdk-core' require_relative 'errors' module RubyConversations # Manages AWS credentials with automatic refresh capability class AwsCredentialProvider class << self def instance @instance ||= new end end def initialize refresh_credentials! end def access_key_id refresh_if_expired! @credentials&.access_key_id end def secret_access_key refresh_if_expired! @credentials&.secret_access_key end def session_token refresh_if_expired! @credentials&.session_token end attr_reader :expiration def refresh_credentials! fetch_and_set_credentials end def refresh_if_expired! return unless expired? refresh_credentials! end private def fetch_and_set_credentials if use_mock_credentials? set_mock_credentials else fetch_and_set_real_credentials end end def use_mock_credentials? ENV['RAILS_ENV'] == 'test' end def set_mock_credentials @credentials = Aws::Credentials.new( 'mock_access_key_id', 'mock_secret_access_key', 'mock_session_token' ) @expiration = Time.now + 3600 # 1 hour end def fetch_and_set_real_credentials ecs_credentials = Aws::CredentialProviderChain.new.resolve raise ConfigurationError, 'Could not resolve AWS credentials' if ecs_credentials.nil? refresh_if_supported(ecs_credentials) assign_credentials(ecs_credentials) end def refresh_if_supported(credentials) credentials.refresh! if credentials.respond_to?(:refresh!) end def assign_credentials(ecs_credentials) if ecs_credentials.respond_to?(:credentials) @credentials = ecs_credentials.credentials @expiration = ecs_credentials.expiration if ecs_credentials.respond_to?(:expiration) else @credentials = ecs_credentials @expiration = nil end end def expired? return false if @expiration.nil? return true if @credentials.nil? # Refresh if we're within 5 minutes of expiration @expiration < Time.now + 300 end end end