diff --git a/Gemfile b/Gemfile index f3d30946a77..6a6fe862c20 100644 --- a/Gemfile +++ b/Gemfile @@ -13,7 +13,7 @@ gem 'aws-sdk-ses', '~> 1.6' gem 'aws-sdk-sns' gem 'barby', '~> 0.6.8' gem 'base32-crockford' -gem 'bootsnap', '~> 1.9.0', require: false +gem 'bootsnap', '~> 1.0', require: false gem 'browser' gem 'connection_pool' gem 'cssbundling-rails' @@ -93,9 +93,9 @@ group :development, :test do gem 'bullet', '~> 7.0' gem 'capybara-webmock', git: 'https://github.com/hashrocket/capybara-webmock.git', ref: 'd3f3b7c' gem 'erb_lint', '~> 0.3.0', require: false - gem 'i18n-tasks', '>= 0.9.31' + gem 'i18n-tasks', '~> 1.0' gem 'knapsack' - gem 'nokogiri', '1.14.0.rc1' + gem 'nokogiri', '~> 1.14.0' gem 'parallel_tests' gem 'pg_query', require: false gem 'pry-byebug' diff --git a/Gemfile.lock b/Gemfile.lock index b64ab9b8a32..ab0c3070e74 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -186,8 +186,8 @@ GEM bindata (2.4.10) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) - bootsnap (1.9.4) - msgpack (~> 1.0) + bootsnap (1.15.0) + msgpack (~> 1.2) brakeman (5.4.0) browser (5.3.1) builder (3.2.4) @@ -221,7 +221,7 @@ GEM crack (0.4.5) rexml crass (1.0.6) - css_parser (1.11.0) + css_parser (1.14.0) addressable cssbundling-rails (1.0.0) railties (>= 6.0.0) @@ -322,15 +322,16 @@ GEM hashie (4.1.0) heapy (0.2.0) thor - highline (2.0.3) + highline (2.1.0) htmlbeautifier (1.4.2) htmlentities (4.3.4) http_accept_language (2.1.1) i18n (1.12.0) concurrent-ruby (~> 1.0) - i18n-tasks (0.9.37) + i18n-tasks (1.0.12) activesupport (>= 4.0.2) ast (>= 2.1.0) + better_html (>= 1.0, < 3.0) erubi highline (>= 2.0.0) i18n @@ -410,9 +411,9 @@ GEM net-protocol timeout net-ssh (6.1.0) - newrelic_rpm (8.12.0) + newrelic_rpm (8.15.0) nio4r (2.5.8) - nokogiri (1.14.0.rc1) + nokogiri (1.14.0) mini_portile2 (~> 2.8.0) racc (~> 1.4) notiffany (0.1.3) @@ -505,7 +506,7 @@ GEM ruby-graphviz (~> 1.2) rails-html-sanitizer (1.4.4) loofah (~> 2.19, >= 2.19.1) - rails-i18n (7.0.3) + rails-i18n (7.0.6) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) railties (7.0.4) @@ -522,12 +523,15 @@ GEM ffi (~> 1.0) redacted_struct (1.1.0) redcarpet (3.5.1) - redis (4.7.1) + redis (5.0.5) + redis-client (>= 0.9.0) + redis-client (0.12.0) + connection_pool redis-namespace (1.8.1) redis (>= 3.0.4) - redis-session-store (0.11.4) - actionpack (>= 3, < 8) - redis (>= 3, < 5) + redis-session-store (0.11.5) + actionpack (>= 6, < 8) + redis (>= 3, < 6) regexp_parser (2.6.1) reline (0.2.7) io-console (~> 0.5) @@ -657,7 +661,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.8) - unicode-display_width (2.4.0) + unicode-display_width (2.4.2) uniform_notifier (1.16.0) valid_email (0.1.4) activemodel @@ -727,7 +731,7 @@ DEPENDENCIES base32-crockford better_errors (>= 2.5.1) binding_of_caller - bootsnap (~> 1.9.0) + bootsnap (~> 1.0) brakeman browser bullet (~> 7.0) @@ -749,7 +753,7 @@ DEPENDENCIES guard-rspec hashie (~> 4.1) http_accept_language - i18n-tasks (>= 0.9.31) + i18n-tasks (~> 1.0) identity-hostdata! identity-logging! identity_validations! @@ -765,7 +769,7 @@ DEPENDENCIES multiset net-sftp newrelic_rpm (~> 8.0) - nokogiri (= 1.14.0.rc1) + nokogiri (~> 1.14.0) octokit (>= 4.25.0) parallel_tests pg diff --git a/app/components/language_picker_component.rb b/app/components/language_picker_component.rb index 0ed01910029..0c13fbbc8ce 100644 --- a/app/components/language_picker_component.rb +++ b/app/components/language_picker_component.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class LanguagePickerComponent < BaseComponent attr_reader :tag_options diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index fe78dc08a37..51558d486dd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationController < ActionController::Base include VerifyProfileConcern include LocaleHelper diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index b4876804a57..58a8b12de18 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users class SessionsController < Devise::SessionsController include ::ActionView::Helpers::DateHelper diff --git a/app/forms/openid_connect_authorize_form.rb b/app/forms/openid_connect_authorize_form.rb index 732d20264dd..40ce4cebb06 100644 --- a/app/forms/openid_connect_authorize_form.rb +++ b/app/forms/openid_connect_authorize_form.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class OpenidConnectAuthorizeForm include ActiveModel::Model include ActionView::Helpers::TranslationHelper diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 381782848e4..d65dca9f358 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationHelper def title(title) content_for(:title) { title } diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb index 6511948b341..8b2681c8fde 100644 --- a/app/helpers/link_helper.rb +++ b/app/helpers/link_helper.rb @@ -1,12 +1,12 @@ -module LinkHelper - EXTERNAL_LINK_CLASS = 'usa-link--external'.freeze +# frozen_string_literal: true +module LinkHelper def new_window_link_to(name = nil, options = nil, html_options = nil, &block) html_options, options, name = options, name, capture(&block) if block html_options ||= {} html_options[:target] = '_blank' - html_options[:class] = [*html_options[:class], EXTERNAL_LINK_CLASS] + html_options[:class] = [*html_options[:class], 'usa-link--external'] name = ERB::Util.unwrapped_html_escape(name).rstrip.html_safe # rubocop:disable Rails/OutputSafety name << content_tag('span', t('links.new_window'), class: 'usa-sr-only') diff --git a/app/helpers/script_helper.rb b/app/helpers/script_helper.rb index e6124b2b179..2a25870c853 100644 --- a/app/helpers/script_helper.rb +++ b/app/helpers/script_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # rubocop:disable Rails/HelperInstanceVariable module ScriptHelper def javascript_include_tag_without_preload(...) diff --git a/app/models/anonymous_user.rb b/app/models/anonymous_user.rb index 6675713d195..7d40550945c 100644 --- a/app/models/anonymous_user.rb +++ b/app/models/anonymous_user.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AnonymousUser def uuid 'anonymous-uuid' diff --git a/app/services/browser_cache.rb b/app/services/browser_cache.rb index b13bcdf42c2..a72c9fd0b02 100644 --- a/app/services/browser_cache.rb +++ b/app/services/browser_cache.rb @@ -1,15 +1,17 @@ class BrowserCache @cache = LruRedux::Cache.new(1_000) + DEFAULT_BROWSER = Browser.new(nil) + USER_AGENT_SIZE = Browser.user_agent_size_limit - 1 # Detects browser attributes from User-Agent, truncated to 2047 bytes due # to: https://github.com/fnando/browser/blob/fa4f685482c315b8/lib/browser/browser.rb#L64-L65 # @param [String] user_agent # @return [Browser] def self.parse(user_agent) - return Browser.new(nil) if user_agent.nil? + return DEFAULT_BROWSER if user_agent.nil? @cache.getset(user_agent) do - Browser.new(user_agent.mb_chars.limit(Browser.user_agent_size_limit - 1).to_s) + Browser.new(user_agent.mb_chars.limit(USER_AGENT_SIZE).to_s) end end diff --git a/app/services/encryption/aes_cipher.rb b/app/services/encryption/aes_cipher.rb index c020e9d723b..70c8cc321e6 100644 --- a/app/services/encryption/aes_cipher.rb +++ b/app/services/encryption/aes_cipher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Encryption class AesCipher include Encodable diff --git a/app/services/encryption/kms_client.rb b/app/services/encryption/kms_client.rb index 648d5d731fe..36830b43e9d 100644 --- a/app/services/encryption/kms_client.rb +++ b/app/services/encryption/kms_client.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'base64' module Encryption @@ -9,6 +11,8 @@ class KmsClient KMS: 'KMSc', LOCAL_KEY: 'LOCc', }.freeze + KMS_KEY_REGEX = /\A#{KEY_TYPE[:KMS]}/ + LOCAL_KEY_REGEX = /\A#{KEY_TYPE[:LOCAL_KEY]}/ def encrypt(plaintext, encryption_context) KmsLogger.log(:encrypt, encryption_context) @@ -55,7 +59,7 @@ def encrypt_raw_kms(plaintext, encryption_context) end def decrypt_kms(ciphertext, encryption_context) - clipped_ciphertext = ciphertext.gsub(/\A#{KEY_TYPE[:KMS]}/, '') + clipped_ciphertext = ciphertext.gsub(KMS_KEY_REGEX, '') ciphertext_chunks = JSON.parse(clipped_ciphertext) ciphertext_chunks.map do |chunk| decrypt_raw_kms( @@ -82,7 +86,7 @@ def encrypt_local(plaintext, encryption_context) end def decrypt_local(ciphertext, encryption_context) - clipped_ciphertext = ciphertext.gsub(/\A#{KEY_TYPE[:LOCAL_KEY]}/, '') + clipped_ciphertext = ciphertext.gsub(LOCAL_KEY_REGEX, '') ciphertext_chunks = JSON.parse(clipped_ciphertext) ciphertext_chunks.map do |chunk| encryptor.decrypt( diff --git a/app/services/ial_context.rb b/app/services/ial_context.rb index ac1af1bb50d..ceeed8c283c 100644 --- a/app/services/ial_context.rb +++ b/app/services/ial_context.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Wraps up logic for querying the IAL level of an authorization request class IalContext attr_reader :ial, :service_provider, :user, :authn_context_comparison diff --git a/app/services/marketing_site.rb b/app/services/marketing_site.rb index 2b0fabdda26..d5ecb1e2488 100644 --- a/app/services/marketing_site.rb +++ b/app/services/marketing_site.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'set' class MarketingSite diff --git a/app/services/openid_connect_attribute_scoper.rb b/app/services/openid_connect_attribute_scoper.rb index 4f3951bac21..81a869b230d 100644 --- a/app/services/openid_connect_attribute_scoper.rb +++ b/app/services/openid_connect_attribute_scoper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class OpenidConnectAttributeScoper X509_SCOPES = %w[ x509 diff --git a/app/services/secure_headers_allow_list.rb b/app/services/secure_headers_allow_list.rb index 05dd65a1358..44e030976a7 100644 --- a/app/services/secure_headers_allow_list.rb +++ b/app/services/secure_headers_allow_list.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SecureHeadersAllowList def self.csp_with_sp_redirect_uris(action_url_domain, sp_redirect_uris) ["'self'"] + reduce_sp_redirect_uris_for_csp([action_url_domain, *sp_redirect_uris].compact) diff --git a/config/application.rb b/config/application.rb index 350480e6887..c6f386ca6a9 100644 --- a/config/application.rb +++ b/config/application.rb @@ -90,6 +90,8 @@ class Application < Rails::Application config.i18n.default_locale = :en config.action_controller.per_form_csrf_tokens = true + config.action_view.frozen_string_literal = true + routes.default_url_options[:host] = IdentityConfig.store.domain_name config.action_mailer.default_options = { diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 2ec1d10a032..3a211b56284 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -99,6 +99,8 @@ ignore_unused: - 'errors.messages.*' - 'simple_form.*' - 'time.*' + - 'idv.failure.attempts.one' + - 'idv.failure.attempts.other' ## Exclude these keys from the `i18n-tasks eq-base' report: # ignore_eq_base: # all: diff --git a/config/initializers/ahoy.rb b/config/initializers/ahoy.rb index e24e13fdee3..d260779917b 100644 --- a/config/initializers/ahoy.rb +++ b/config/initializers/ahoy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'utf8_cleaner' Ahoy.api = false diff --git a/config/initializers/secure_headers.rb b/config/initializers/secure_headers.rb index f4d9078d342..bfd13428d88 100644 --- a/config/initializers/secure_headers.rb +++ b/config/initializers/secure_headers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Rails.application.configure do config.ssl_options = { secure_cookies: true, diff --git a/lib/asset_sources.rb b/lib/asset_sources.rb index 1e2579d4922..8766571fbc4 100644 --- a/lib/asset_sources.rb +++ b/lib/asset_sources.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AssetSources class << self attr_accessor :manifest_path diff --git a/lib/rack_request_parser.rb b/lib/rack_request_parser.rb index ff174639aea..49ce9d43d6a 100644 --- a/lib/rack_request_parser.rb +++ b/lib/rack_request_parser.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RackRequestParser attr_reader :request diff --git a/lib/secure_cookies.rb b/lib/secure_cookies.rb index dc0cf0e83aa..b432ba90cce 100644 --- a/lib/secure_cookies.rb +++ b/lib/secure_cookies.rb @@ -1,6 +1,11 @@ +# frozen_string_literal: true + # Reimplements SecureHeaders secure cookie functionality to make sure all cookies are secure class SecureCookies - COOKIE_SEPARATOR = "\n".freeze + COOKIE_SEPARATOR = "\n" + SECURE_REGEX = /; Secure/i + HTTP_ONLY_REGEX = /; HttpOnly/i + SAME_SITE_REGEX = /; SameSite/i def initialize(app) @app = app @@ -15,9 +20,9 @@ def call(env) cookies.each do |cookie| next if cookie.blank? - cookie << '; Secure' if env['HTTPS'] == 'on' && !cookie.match?(/; Secure/i) - cookie << '; HttpOnly' if !cookie.match?(/; HttpOnly/i) - cookie << '; SameSite=Lax' if !cookie.match?(/; SameSite/i) + cookie << '; Secure' if env['HTTPS'] == 'on' && !cookie.match?(SECURE_REGEX) + cookie << '; HttpOnly' if !cookie.match?(HTTP_ONLY_REGEX) + cookie << '; SameSite=Lax' if !cookie.match?(SAME_SITE_REGEX) end headers['Set-Cookie'] = cookies.join(COOKIE_SEPARATOR) diff --git a/lib/session_encryptor.rb b/lib/session_encryptor.rb index c62a1081b17..57aae4a88cc 100644 --- a/lib/session_encryptor.rb +++ b/lib/session_encryptor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SessionEncryptor class SensitiveKeyError < StandardError; end diff --git a/lib/utf8_cleaner.rb b/lib/utf8_cleaner.rb index e49d806c7d7..2893092d802 100644 --- a/lib/utf8_cleaner.rb +++ b/lib/utf8_cleaner.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Utf8Cleaner attr_reader :string diff --git a/lib/utf8_sanitizer.rb b/lib/utf8_sanitizer.rb index fca5f96d50c..965da0067ad 100644 --- a/lib/utf8_sanitizer.rb +++ b/lib/utf8_sanitizer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rack_request_parser' require 'utf8_cleaner'