From 47f72ce0cd186358057f179f5bc2f8fedef4136e Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 26 Jun 2024 12:11:23 +0300 Subject: [PATCH 1/6] added prepend action to format foreign symbols to punicode --- Dockerfile | 3 ++ Gemfile | 1 + Gemfile.lock | 10 +++++-- app/controllers/application_controller.rb | 34 +++++++++++++++-------- app/controllers/users_controller.rb | 6 +++- config/environments/development.rb | 2 +- config/routes.rb | 1 + test/integration/users_test.rb | 27 ++++++++++++++++++ 8 files changed, 69 insertions(+), 15 deletions(-) diff --git a/Dockerfile b/Dockerfile index 282e11ae0..7da75a3bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,9 @@ RUN yarn install --frozen-lockfile FROM base +ENV LAUNCHY_DRY_RUN=true +ENV BROWSER=/dev/null + RUN useradd rails RUN mkdir -p /home/rails && chown rails:rails /home/rails diff --git a/Gemfile b/Gemfile index 09b7466f1..651b0ef75 100644 --- a/Gemfile +++ b/Gemfile @@ -66,6 +66,7 @@ group :development do gem 'htmlbeautifier' gem 'i18n-debug' gem 'letter_opener', '~> 1.8' + gem 'letter_opener_web', '~> 3.0' gem 'listen', '>= 3.0.5', '< 3.9' gem 'ruby-lsp-rails' gem 'web-console', '>= 3.3.0' diff --git a/Gemfile.lock b/Gemfile.lock index 8122eef9f..dde6b7b68 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -208,8 +208,13 @@ GEM language_server-protocol (3.17.0.3) launchy (2.5.2) addressable (~> 2.8) - letter_opener (1.8.1) - launchy (>= 2.2, < 3) + letter_opener (1.10.0) + launchy (>= 2.2, < 4) + letter_opener_web (3.0.0) + actionmailer (>= 6.1) + letter_opener (~> 1.9) + railties (>= 6.1) + rexml listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -503,6 +508,7 @@ DEPENDENCIES jsbundling-rails jwt letter_opener (~> 1.8) + letter_opener_web (~> 3.0) listen (>= 3.0.5, < 3.9) lograge mimemagic (~> 0.4.3) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2a6b07b5f..0d0b6ecfc 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,17 +1,19 @@ class ApplicationController < ActionController::Base include Pagy::Backend + prepend_before_action :convert_punycode_params + helper_method :turbo_frame_request? protect_from_forgery with: :exception before_action :set_locale, :clear_flash - before_action :set_notifications + before_action :notifications_for_header content_security_policy do |policy| policy.style_src :self, 'www.gstatic.com', :unsafe_inline end - rescue_from CanCan::AccessDenied do |exception| + rescue_from CanCan::AccessDenied do |_exception| flash[:alert] = I18n.t('unauthorized.message') if turbo_frame_request? @@ -22,7 +24,9 @@ class ApplicationController < ActionController::Base end def store_location - session[:return_to] = request.referer.split('?').first if request.referer + return unless request.referer + + session[:return_to] = request.referer.split('?').first end # If needed, add updated_by to the params hash. Updated by takes format of "123 - User Surname" @@ -36,30 +40,38 @@ def merge_updated_by(update_params) end end - def after_sign_in_path_for(_resource) - root_path - end + def after_sign_in_path_for(_resource) = root_path - def set_notifications + def notifications_for_header # don't change the name, it's used in the header and can be conflict with notification variable in notifications page - @notifications_for_header = current_user&.notifications&.unread&.order(created_at: :desc)&.limit(5) + @notifications_for_header ||= current_user&.notifications&.unread&.order(created_at: :desc)&.limit(5) end private def set_locale - if params[:localize].present? && I18n.available_locales.include?(params[:localize].to_sym) - cookies[:locale] = params[:localize] - end + set_locale_to_cookies I18n.locale = current_user&.locale || cookies[:locale] || I18n.default_locale @pagy_locale = I18n.locale.to_s end + def set_locale_to_cookies + return unless params[:localize].present? && I18n.available_locales.include?(params[:localize].to_sym) + + cookies[:locale] = params[:localize] + end + def clear_flash flash.clear if turbo_frame_request? end + def convert_punycode_params + return unless email = request.params.dig(:user, :email) + + request.params[:user][:email] = email.split('@').map { |val| SimpleIDN.to_ascii(val) }.join('@') + end + protected def authenticate_user! diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index f88af127d..d44ee03d8 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -42,6 +42,8 @@ def create respond_to do |format| if @user.save + flash[:notice] = t(:created) + format.html do sign_in(User, @user) redirect_to user_path(@user.uuid), notice: t(:created) @@ -52,7 +54,9 @@ def create render :show, status: :created, location: @user end else - format.html { render :new } + flash.now[:alert] = @user.errors.full_messages.join(', ') + + format.html { render :new, status: :unprocessable_entity } format.json { render json: @user.errors, status: :unprocessable_entity } end end diff --git a/config/environments/development.rb b/config/environments/development.rb index bb8880009..fdb594521 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -50,7 +50,7 @@ config.active_record.verbose_query_logs = true config.log_formatter = ::Logger::Formatter.new - config.action_mailer.delivery_method = :letter_opener + config.action_mailer.delivery_method = :letter_opener_web config.action_mailer.default_url_options = { host: 'localhost:3000', protocol: 'http' diff --git a/config/routes.rb b/config/routes.rb index 85e17fb0f..b202d82f0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -144,4 +144,5 @@ resources :autobider, param: :uuid, only: [:create, :update, :edit, :new] mount OkComputer::Engine, at: '/healthcheck', as: :healthcheck + mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? end diff --git a/test/integration/users_test.rb b/test/integration/users_test.rb index 51262608c..4a6c0f70d 100644 --- a/test/integration/users_test.rb +++ b/test/integration/users_test.rb @@ -22,4 +22,31 @@ def test_user_is_notified_about_password_change password_confirmation: new_password } } end end + + def test_user_create_with_punicode + assert_enqueued_emails 1 do + post users_path, params: { + user: { + email: 'example@ää.eu', + given_names: 'John', + surname: 'Doe', + password: 'password123', + password_confirmation: 'password123', + terms_and_conditions_accepted_at: Time.now.utc, + locale: 'en', + mobile_phone: '+37269900366', + identity_code: '60001017793', + country_code: 'EE', + accepts_terms_and_conditions: true, + roles: ['participant'], + phone_number_confirmed: true, + provider: 'email'} + } + end + + punicode = SimpleIDN.to_ascii('ää.eu') + assert User.find_by(email: "example@#{punicode}") + + assert_redirected_to new_user_session_path + end end From 84e358b205e04906a6da619f76de192e6aceae8e Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 26 Jun 2024 12:42:23 +0300 Subject: [PATCH 2/6] added smtputf8 to header --- app/controllers/application_controller.rb | 10 +++++----- app/mailers/application_mailer.rb | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0d0b6ecfc..20f49dd51 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,7 +1,7 @@ class ApplicationController < ActionController::Base include Pagy::Backend - prepend_before_action :convert_punycode_params + # prepend_before_action :convert_punycode_params helper_method :turbo_frame_request? @@ -66,11 +66,11 @@ def clear_flash flash.clear if turbo_frame_request? end - def convert_punycode_params - return unless email = request.params.dig(:user, :email) + # def convert_punycode_params + # return unless email = request.params.dig(:user, :email) - request.params[:user][:email] = email.split('@').map { |val| SimpleIDN.to_ascii(val) }.join('@') - end + # request.params[:user][:email] = email.split('@').map { |val| SimpleIDN.to_ascii(val) }.join('@') + # end protected diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 15ae263d8..cbfe8e59e 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,4 +1,12 @@ class ApplicationMailer < ActionMailer::Base + before_action :add_smtputf8_header + default from: Rails.application.config.customization['email_from_address'] layout 'mailer' + + private + + def add_smtputf8_header + headers['SMTPUTF8'] = 'true' + end end From d6a1163edf3c74a76d3b0c2172c39f801e96fe5f Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 26 Jun 2024 12:45:32 +0300 Subject: [PATCH 3/6] comment out test --- test/integration/users_test.rb | 52 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/test/integration/users_test.rb b/test/integration/users_test.rb index 4a6c0f70d..e5007c31c 100644 --- a/test/integration/users_test.rb +++ b/test/integration/users_test.rb @@ -23,30 +23,30 @@ def test_user_is_notified_about_password_change end end - def test_user_create_with_punicode - assert_enqueued_emails 1 do - post users_path, params: { - user: { - email: 'example@ää.eu', - given_names: 'John', - surname: 'Doe', - password: 'password123', - password_confirmation: 'password123', - terms_and_conditions_accepted_at: Time.now.utc, - locale: 'en', - mobile_phone: '+37269900366', - identity_code: '60001017793', - country_code: 'EE', - accepts_terms_and_conditions: true, - roles: ['participant'], - phone_number_confirmed: true, - provider: 'email'} - } - end - - punicode = SimpleIDN.to_ascii('ää.eu') - assert User.find_by(email: "example@#{punicode}") - - assert_redirected_to new_user_session_path - end + # def test_user_create_with_punicode + # assert_enqueued_emails 1 do + # post users_path, params: { + # user: { + # email: 'example@ää.eu', + # given_names: 'John', + # surname: 'Doe', + # password: 'password123', + # password_confirmation: 'password123', + # terms_and_conditions_accepted_at: Time.now.utc, + # locale: 'en', + # mobile_phone: '+37269900366', + # identity_code: '60001017793', + # country_code: 'EE', + # accepts_terms_and_conditions: true, + # roles: ['participant'], + # phone_number_confirmed: true, + # provider: 'email'} + # } + # end + + # punicode = SimpleIDN.to_ascii('ää.eu') + # assert User.find_by(email: "example@#{punicode}") + + # assert_redirected_to new_user_session_path + # end end From 73ed31e67284ceee34bfe9be00cfff2fff0a1858 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 26 Jun 2024 13:21:36 +0300 Subject: [PATCH 4/6] added dynamic parser idn email domain --- app/controllers/application_controller.rb | 8 -------- app/mailers/application_mailer.rb | 13 +++++++++++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 20f49dd51..d7b9c926d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,8 +1,6 @@ class ApplicationController < ActionController::Base include Pagy::Backend - # prepend_before_action :convert_punycode_params - helper_method :turbo_frame_request? protect_from_forgery with: :exception @@ -66,12 +64,6 @@ def clear_flash flash.clear if turbo_frame_request? end - # def convert_punycode_params - # return unless email = request.params.dig(:user, :email) - - # request.params[:user][:email] = email.split('@').map { |val| SimpleIDN.to_ascii(val) }.join('@') - # end - protected def authenticate_user! diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index cbfe8e59e..acdc40b30 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,5 +1,6 @@ class ApplicationMailer < ActionMailer::Base before_action :add_smtputf8_header + before_action :convert_email_to_punycode default from: Rails.application.config.customization['email_from_address'] layout 'mailer' @@ -9,4 +10,16 @@ class ApplicationMailer < ActionMailer::Base def add_smtputf8_header headers['SMTPUTF8'] = 'true' end + + def convert_email_to_punycode + mail.to = Array(mail.to).map { |email| convert_domain_to_punycode(email) } + mail.cc = Array(mail.cc).map { |email| convert_domain_to_punycode(email) } + mail.bcc = Array(mail.bcc).map { |email| convert_domain_to_punycode(email) } + end + + def convert_domain_to_punycode(email) + local, domain = email.split('@') + domain = SimpleIDN.to_ascii(domain) + "#{local}@#{domain}" + end end From 3e0193b19a2fb95b0f760d7550d92c1b6b2d849f Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 26 Jun 2024 14:14:36 +0300 Subject: [PATCH 5/6] changed callback --- app/mailers/application_mailer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index acdc40b30..a158947da 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,6 +1,6 @@ class ApplicationMailer < ActionMailer::Base before_action :add_smtputf8_header - before_action :convert_email_to_punycode + after_action :convert_email_to_punycode default from: Rails.application.config.customization['email_from_address'] layout 'mailer' From 1930ec2493dbf3315d025a8c9cee2a2c0ac65a9e Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Wed, 26 Jun 2024 14:45:53 +0300 Subject: [PATCH 6/6] remove test --- app/mailers/application_mailer.rb | 12 ++++++++++++ test/integration/users_test.rb | 27 --------------------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index a158947da..18a574c30 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -12,8 +12,20 @@ def add_smtputf8_header end def convert_email_to_punycode + convert_recipient_to_punycode + convert_carbon_copy_to_punycode + convert_blind_carbon_copy_to_punycode + end + + def convert_recipient_to_punycode mail.to = Array(mail.to).map { |email| convert_domain_to_punycode(email) } + end + + def convert_carbon_copy_to_punycode mail.cc = Array(mail.cc).map { |email| convert_domain_to_punycode(email) } + end + + def convert_blind_carbon_copy_to_punycode mail.bcc = Array(mail.bcc).map { |email| convert_domain_to_punycode(email) } end diff --git a/test/integration/users_test.rb b/test/integration/users_test.rb index e5007c31c..51262608c 100644 --- a/test/integration/users_test.rb +++ b/test/integration/users_test.rb @@ -22,31 +22,4 @@ def test_user_is_notified_about_password_change password_confirmation: new_password } } end end - - # def test_user_create_with_punicode - # assert_enqueued_emails 1 do - # post users_path, params: { - # user: { - # email: 'example@ää.eu', - # given_names: 'John', - # surname: 'Doe', - # password: 'password123', - # password_confirmation: 'password123', - # terms_and_conditions_accepted_at: Time.now.utc, - # locale: 'en', - # mobile_phone: '+37269900366', - # identity_code: '60001017793', - # country_code: 'EE', - # accepts_terms_and_conditions: true, - # roles: ['participant'], - # phone_number_confirmed: true, - # provider: 'email'} - # } - # end - - # punicode = SimpleIDN.to_ascii('ää.eu') - # assert User.find_by(email: "example@#{punicode}") - - # assert_redirected_to new_user_session_path - # end end