From 6b793a259d0bc467b1ad9c4671c6edcf6cad6439 Mon Sep 17 00:00:00 2001 From: Richard Hatherall Date: Tue, 3 Mar 2026 21:31:30 +0000 Subject: [PATCH] fix: Tighten UserInfo and attr mutability Delegate respond_to_missing? to the underlying OpenStruct so it only returns true for attributes that exist, rather than for any method name. Change attr_accessor to attr_reader on Client, AuthorizationUri, and LogoutUri to prevent mutation after init. --- lib/cognito_idp/authorization_uri.rb | 2 +- lib/cognito_idp/client.rb | 2 +- lib/cognito_idp/logout_uri.rb | 2 +- lib/cognito_idp/user_info.rb | 2 +- spec/cognito_idp/user_info_spec.rb | 12 ++++++++++++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/cognito_idp/authorization_uri.rb b/lib/cognito_idp/authorization_uri.rb index 0515e19..6dcd784 100644 --- a/lib/cognito_idp/authorization_uri.rb +++ b/lib/cognito_idp/authorization_uri.rb @@ -2,7 +2,7 @@ module CognitoIdp class AuthorizationUri - attr_accessor :client_id, :code_challenge_method, :code_challenge, :domain, + attr_reader :client_id, :code_challenge_method, :code_challenge, :domain, :idp_identifier, :identity_provider, :nonce, :redirect_uri, :response_type, :scope, :state diff --git a/lib/cognito_idp/client.rb b/lib/cognito_idp/client.rb index 9ba64eb..751d98d 100644 --- a/lib/cognito_idp/client.rb +++ b/lib/cognito_idp/client.rb @@ -5,7 +5,7 @@ module CognitoIdp class Client - attr_accessor :adapter, :client_id, :client_secret, :domain + attr_reader :adapter, :client_id, :client_secret, :domain def initialize(client_id:, domain:, client_secret: nil, adapter: Faraday.default_adapter, stubs: nil) @adapter = adapter diff --git a/lib/cognito_idp/logout_uri.rb b/lib/cognito_idp/logout_uri.rb index 25265e9..9690df6 100644 --- a/lib/cognito_idp/logout_uri.rb +++ b/lib/cognito_idp/logout_uri.rb @@ -2,7 +2,7 @@ module CognitoIdp class LogoutUri - attr_accessor :client_id, :domain, :logout_uri, :redirect_uri, :response_type, :scope, :state + attr_reader :client_id, :domain, :logout_uri, :redirect_uri, :response_type, :scope, :state def initialize(client_id:, domain:, **options) @client_id = client_id diff --git a/lib/cognito_idp/user_info.rb b/lib/cognito_idp/user_info.rb index 1ac60f4..e420fca 100644 --- a/lib/cognito_idp/user_info.rb +++ b/lib/cognito_idp/user_info.rb @@ -14,7 +14,7 @@ def method_missing(method, ...) end def respond_to_missing?(method, include_private = false) - true + @attributes.respond_to?(method, include_private) || super end end end diff --git a/spec/cognito_idp/user_info_spec.rb b/spec/cognito_idp/user_info_spec.rb index 4df49cd..21e679b 100644 --- a/spec/cognito_idp/user_info_spec.rb +++ b/spec/cognito_idp/user_info_spec.rb @@ -17,6 +17,18 @@ it { expect(user_info.email_verified).to be_nil } it { expect(user_info.phone_number_verified).to be_nil } + describe "#respond_to?" do + context "when attribute exists" do + let(:user_info_hash) { {"email" => "jane@example.com"} } + + it { expect(user_info).to respond_to(:email) } + end + + context "when attribute does not exist" do + it { expect(user_info).not_to respond_to(:nonexistent) } + end + end + context "when given attributes" do let(:user_info_hash) do {