From 34cf04ca4077c801ab7a468e737fa6c8591f8583 Mon Sep 17 00:00:00 2001 From: Daniel Pierce Date: Thu, 15 Jun 2023 15:40:48 -0400 Subject: [PATCH] Backport #6063 (Google privkey in ENV) to 3.x --- .dassie/config/analytics.yml | 4 +- .regen | 3 +- app/services/hyrax/analytics/google.rb | 38 +++++++++++-------- app/services/hyrax/analytics/matomo.rb | 7 ++-- .../hyrax/templates/config/analytics.yml | 1 + spec/lib/hyrax/analytics_spec.rb | 16 +++++--- .../lib/generators/test_app_generator.rb | 1 + 7 files changed, 43 insertions(+), 27 deletions(-) diff --git a/.dassie/config/analytics.yml b/.dassie/config/analytics.yml index e48b87578a..a84eb18463 100644 --- a/.dassie/config/analytics.yml +++ b/.dassie/config/analytics.yml @@ -3,11 +3,11 @@ analytics: analytics_id: <%= ENV['GOOGLE_ANALYTICS_ID'] %> app_name: <%= ENV['GOOGLE_OAUTH_APP_NAME'] %> app_version: <%= ENV['GOOGLE_OAUTH_APP_VERSION'] %> + privkey_value: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_VALUE'] %> privkey_path: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_PATH'] %> privkey_secret: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_SECRET'] %> client_email: <%= ENV['GOOGLE_OAUTH_CLIENT_EMAIL'] %> - matomo: + matomo: base_url: <%= ENV['MATOMO_BASE_URL'] %> site_id: <%= ENV['MATOMO_SITE_ID'] %> auth_token: <%= ENV['MATOMO_AUTH_TOKEN'] %> - \ No newline at end of file diff --git a/.regen b/.regen index 9e5feb5256..929004c8bf 100644 --- a/.regen +++ b/.regen @@ -1 +1,2 @@ -46 +# When updating CI regen seed, set to current date. +2023-05-24T10:43:07 diff --git a/app/services/hyrax/analytics/google.rb b/app/services/hyrax/analytics/google.rb index 3dbb2b7c4d..1ff9d19837 100644 --- a/app/services/hyrax/analytics/google.rb +++ b/app/services/hyrax/analytics/google.rb @@ -1,20 +1,24 @@ # frozen_string_literal: true + require 'oauth2' require 'signet/oauth_2/client' -# rubocop:disable Metrics/ModuleLength module Hyrax module Analytics + # rubocop:disable Metrics/ModuleLength module Google extend ActiveSupport::Concern # rubocop:disable Metrics/BlockLength class_methods do - # Loads configuration options from config/analytics.yml. Expected structure: + # Loads configuration options from config/analytics.yml. You only need PRIVATE_KEY_PATH or + # PRIVATE_KEY_VALUE. VALUE takes precedence. + # Expected structure: # `analytics:` # ` google:` # ` app_name: <%= ENV['GOOGLE_OAUTH_APP_NAME']` # ` app_version: <%= ENV['GOOGLE_OAUTH_APP_VERSION']` # ` privkey_path: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_PATH']` + # ` privkey_value: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_VALUE']` # ` privkey_secret: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_SECRET']` # ` client_email: <%= ENV['GOOGLE_OAUTH_CLIENT_EMAIL']` # @return [Config] @@ -41,7 +45,8 @@ def self.load_from_yaml new config end - REQUIRED_KEYS = %w[analytics_id app_name app_version privkey_path privkey_secret client_email].freeze + KEYS = %w[analytics_id app_name app_version privkey_path privkey_value privkey_secret client_email].freeze + REQUIRED_KEYS = %w[analytics_id app_name app_version privkey_secret client_email].freeze def initialize(config) @config = config @@ -49,18 +54,16 @@ def initialize(config) # @return [Boolean] are all the required values present? def valid? - config_keys = @config.keys - REQUIRED_KEYS.all? { |required| config_keys.include?(required) } - end + return false unless @config['privkey_value'].present? || @config['privkey_path'].present? - REQUIRED_KEYS.each do |key| - class_eval %{ def #{key}; @config.fetch('#{key}'); end } + REQUIRED_KEYS.all? { |required| @config[required].present? } end - # This method allows setting the analytics id in the initializer - # @deprecated set the analytics id in either ENV['GOOGLE_ANALYTICS_ID'] or config/analytics.yaml - def analytics_id=(value) - @config['analytics_id'] = value + KEYS.each do |key| + # rubocop:disable Style/EvalWithLocation + class_eval %{ def #{key}; @config.fetch('#{key}'); end } + class_eval %{ def #{key}=(value); @config['#{key}'] = value; end } + # rubocop:enable Style/EvalWithLocation end end @@ -77,8 +80,12 @@ def oauth_client end def auth_client(scope) - raise "Private key file for Google analytics was expected at '#{config.privkey_path}', but no file was found." unless File.exist?(config.privkey_path) - private_key = File.read(config.privkey_path) + private_key = Base64.decode64(config.privkey_value) if config.privkey_value.present? + if private_key.blank? + raise "Private key file for Google analytics was expected at '#{config.privkey_path}', but no file was found." unless File.exist?(config.privkey_path) + + private_key = File.read(config.privkey_path) + end Signet::OAuth2::Client.new token_credential_uri: 'https://accounts.google.com/o/oauth2/token', audience: 'https://accounts.google.com/o/oauth2/token', scope: scope, @@ -123,7 +130,7 @@ def to_date_range(period) [start_date, end_date] end - # rubocop:enabl e Metrics/MethodLength + # rubocop:enable Metrics/MethodLength def keyword_conversion(date) case date @@ -199,6 +206,7 @@ def total_visitors(period = 'month', date = default_date_range) end # rubocop:enable Metrics/BlockLength end + # rubocop:enable Metrics/ModuleLength end end # rubocop:enable Metrics/ModuleLength diff --git a/app/services/hyrax/analytics/matomo.rb b/app/services/hyrax/analytics/matomo.rb index 2e95404adb..7262ffc771 100644 --- a/app/services/hyrax/analytics/matomo.rb +++ b/app/services/hyrax/analytics/matomo.rb @@ -11,15 +11,16 @@ module Matomo # Loads configuration options from config/analytics.yml. Expected structure: # `analytics:` # ` matomo:` - # ` base_url: <%= ENV['MATOMOT_BASE_URL']` - # ` site_id: <%= ENV['MATOMOT_SITE_ID']` - # ` auth_token: <%= ENV['MATOMOT_AUTH_TOKEN']` + # ` base_url: <%= ENV['MATOMO_BASE_URL']` + # ` site_id: <%= ENV['MATOMO_SITE_ID']` + # ` auth_token: <%= ENV['MATOMO_AUTH_TOKEN']` # @return [Config] def config @config ||= Config.load_from_yaml end class Config + # TODO: test matomo and see if it needs any of the updates from https://github.com/samvera/hyrax/pull/6063 def self.load_from_yaml filename = Rails.root.join('config', 'analytics.yml') yaml = YAML.safe_load(ERB.new(File.read(filename)).result) diff --git a/lib/generators/hyrax/templates/config/analytics.yml b/lib/generators/hyrax/templates/config/analytics.yml index bd51d37e96..9153a323bc 100644 --- a/lib/generators/hyrax/templates/config/analytics.yml +++ b/lib/generators/hyrax/templates/config/analytics.yml @@ -6,6 +6,7 @@ analytics: analytics_id: <%= ENV['GOOGLE_ANALYTICS_ID'] %> app_name: <%= ENV['GOOGLE_OAUTH_APP_NAME'] %> app_version: <%= ENV['GOOGLE_OAUTH_APP_VERSION'] %> + privkey_value: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_VALUE'] %> privkey_path: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_PATH'] %> privkey_secret: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_SECRET'] %> client_email: <%= ENV['GOOGLE_OAUTH_CLIENT_EMAIL'] %> diff --git a/spec/lib/hyrax/analytics_spec.rb b/spec/lib/hyrax/analytics_spec.rb index 9458db81db..9a4e1af394 100644 --- a/spec/lib/hyrax/analytics_spec.rb +++ b/spec/lib/hyrax/analytics_spec.rb @@ -2,11 +2,12 @@ RSpec.describe Hyrax::Analytics do before do ENV['GOOGLE_ANALYTICS_ID'] = 'UA-XXXXXXXX' - ENV['GOOGLE_OAUTH_APP_NAME'] = "My App Name" - ENV['GOOGLE_OAUTH_APP_VERSION'] = "0.0.1" - ENV['GOOGLE_OAUTH_PRIVATE_KEY_PATH'] = "/tmp/privkey.p12" - ENV['GOOGLE_OAUTH_PRIVATE_KEY_SECRET'] = "s00pers3kr1t" - ENV['GOOGLE_OAUTH_CLIENT_EMAIL'] = "oauth@example.org" + ENV['GOOGLE_OAUTH_APP_NAME'] = 'My App Name' + ENV['GOOGLE_OAUTH_APP_VERSION'] = '0.0.1' + ENV['GOOGLE_OAUTH_PRIVATE_KEY_PATH'] = '/tmp/privkey.p12' + ENV['GOOGLE_OAUTH_PRIVATE_KEY_VALUE'] = '' + ENV['GOOGLE_OAUTH_PRIVATE_KEY_SECRET'] = 's00pers3kr1t' + ENV['GOOGLE_OAUTH_CLIENT_EMAIL'] = 'oauth@example.org' described_class.send(:remove_instance_variable, :@config) if described_class.send(:instance_variable_defined?, :@config) end @@ -23,6 +24,7 @@ expect(config.analytics_id).to eql 'UA-XXXXXXXX' expect(config.app_name).to eql 'My App Name' expect(config.app_version).to eql '0.0.1' + expect(config.privkey_value).to be_nil expect(config.privkey_path).to eql '/tmp/privkey.p12' expect(config.privkey_secret).to eql 's00pers3kr1t' expect(config.client_email).to eql 'oauth@example.org' @@ -35,6 +37,7 @@ analytics: app_name: My App Name app_version: 0.0.1 + privkey_value: privkey_path: /tmp/privkey.p12 privkey_secret: s00pers3kr1t client_email: oauth@example.org @@ -45,6 +48,7 @@ Hyrax.config.google_analytics_id = "UA-XXXXXXXX" expect(config.app_name).to eql 'My App Name' expect(config.app_version).to eql '0.0.1' + expect(config.privkey_value).to be_nil expect(config.privkey_path).to eql '/tmp/privkey.p12' expect(config.privkey_secret).to eql 's00pers3kr1t' expect(config.client_email).to eql 'oauth@example.org' @@ -79,7 +83,7 @@ describe "#profile" do subject { described_class.profile } - context "when the private key file is missing" do + context "when the private key file and private key value are missing" do it "raises an error" do expect { subject }.to raise_error RuntimeError, "Private key file for Google analytics was expected at '/tmp/privkey.p12', but no file was found." end diff --git a/spec/test_app_templates/lib/generators/test_app_generator.rb b/spec/test_app_templates/lib/generators/test_app_generator.rb index 41694f1aea..f3e2cd1d0d 100644 --- a/spec/test_app_templates/lib/generators/test_app_generator.rb +++ b/spec/test_app_templates/lib/generators/test_app_generator.rb @@ -148,6 +148,7 @@ def add_analytics_config analytics_id: UA-XXXXXXXX app_name: My App Name app_version: 0.0.1 + privkey_value: privkey_path: /tmp/privkey.p12 privkey_secret: s00pers3kr1t client_email: oauth@example.org