diff --git a/.rubocop.yml b/.rubocop.yml index f77a479c6..cfb997da3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -364,6 +364,7 @@ Metrics/ClassLength: - 'packages/forest_admin_agent/lib/forest_admin_agent/routes/resources/related/update_related.rb' - 'packages/forest_admin_agent/lib/forest_admin_agent/routes/workflow/workflow_executor_proxy.rb' - 'packages/forest_admin_agent/lib/forest_admin_agent/services/permissions.rb' + - 'packages/forest_admin_agent/lib/forest_admin_agent/services/ip_whitelist.rb' - 'packages/forest_admin_agent/lib/forest_admin_agent/services/smart_action_checker.rb' - 'packages/forest_admin_agent/lib/forest_admin_agent/utils/schema/frontend_validation_utils.rb' - 'packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb' diff --git a/packages/forest_admin_agent/lib/forest_admin_agent/services/ip_whitelist.rb b/packages/forest_admin_agent/lib/forest_admin_agent/services/ip_whitelist.rb index 828aab407..acfa9899b 100644 --- a/packages/forest_admin_agent/lib/forest_admin_agent/services/ip_whitelist.rb +++ b/packages/forest_admin_agent/lib/forest_admin_agent/services/ip_whitelist.rb @@ -1,4 +1,6 @@ require 'ipaddress' +require 'filecache' +require 'json' module ForestAdminAgent module Services @@ -6,11 +8,26 @@ class IpWhitelist RULE_MATCH_IP = 0 RULE_MATCH_RANGE = 1 RULE_MATCH_SUBNET = 2 + CACHE_KEY = 'forest.ip_whitelist'.freeze - attr_reader :forest_api + attr_reader :forest_api, :cache def initialize @forest_api = ForestAdminAgent::Http::ForestAdminApiRequester.new + @cache = FileCache.new( + 'ip_whitelist', + Facades::Container.config_from_cache[:cache_dir].to_s, + Facades::Container.config_from_cache[:permission_expiration] + ) + end + + def self.invalidate_cache + cache = FileCache.new( + 'ip_whitelist', + Facades::Container.config_from_cache[:cache_dir].to_s, + Facades::Container.config_from_cache[:permission_expiration] + ) + cache.delete(CACHE_KEY) unless cache.get(CACHE_KEY).nil? end def use_ip_whitelist @@ -85,6 +102,13 @@ def ip_match_subnet?(ip, subnet) private def fetch_rules + ip_whitelist_data = cache.get_or_set(CACHE_KEY) { fetch_ip_whitelist_from_api } + + @use_ip_whitelist = ip_whitelist_data['use_ip_whitelist'] + @rules = ip_whitelist_data['rules'] + end + + def fetch_ip_whitelist_from_api response = forest_api.get('/liana/v1/ip-whitelist-rules') unless response.status == 200 @@ -109,10 +133,7 @@ def fetch_rules ForestAdminAgent::Utils::ErrorMessages::UNEXPECTED end - ip_whitelist_data = body['data']['attributes'] - - @use_ip_whitelist = ip_whitelist_data['use_ip_whitelist'] - @rules = ip_whitelist_data['rules'] + body['data']['attributes'] rescue StandardError => e ForestAdminAgent::Facades::Container.logger.log('Debug', { error: e.message, diff --git a/packages/forest_admin_agent/spec/lib/forest_admin_agent/services/ip_whitelist_spec.rb b/packages/forest_admin_agent/spec/lib/forest_admin_agent/services/ip_whitelist_spec.rb index 3cd75b6ee..b18c20120 100644 --- a/packages/forest_admin_agent/spec/lib/forest_admin_agent/services/ip_whitelist_spec.rb +++ b/packages/forest_admin_agent/spec/lib/forest_admin_agent/services/ip_whitelist_spec.rb @@ -10,6 +10,8 @@ module Services let(:forest_api_requester) { instance_double(ForestAdminAgent::Http::ForestAdminApiRequester) } + before { described_class.invalidate_cache } + context 'when there is no rule' do before do allow(forest_api_requester).to receive(:get).with('/liana/v1/ip-whitelist-rules').and_return( @@ -286,6 +288,32 @@ module Services end.to raise_error('Invalid rule type') end end + + context 'when caching whitelist rules' do + before do + allow(forest_api_requester).to receive(:get).with('/liana/v1/ip-whitelist-rules').and_return( + instance_double(Faraday::Response, + status: 200, + body: { + 'data' => { + 'attributes' => { + 'rules' => [], + 'use_ip_whitelist' => false + } + } + }.to_json) + ) + + allow(ForestAdminAgent::Http::ForestAdminApiRequester).to receive(:new).and_return(forest_api_requester) + end + + it 'fetches the rules from the API only once across instances' do + described_class.new.use_ip_whitelist + described_class.new.use_ip_whitelist + + expect(forest_api_requester).to have_received(:get).once + end + end end end end diff --git a/packages/forest_admin_agent/spec/spec_helper.rb b/packages/forest_admin_agent/spec/spec_helper.rb index d6f74e967..d7148dd8c 100644 --- a/packages/forest_admin_agent/spec/spec_helper.rb +++ b/packages/forest_admin_agent/spec/spec_helper.rb @@ -51,6 +51,7 @@ forest_server_url: 'https://api.development.forestadmin.com', debug: true, prefix: 'forest', + permission_expiration: 100, customize_error_message: nil, append_schema_path: nil }