Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - `app/controllers/about_controller.rb`: Minor conflict caused by glitch-soc's theming system. Ported upstream changes.
This commit is contained in:
		
						commit
						7782e4dc0d
					
				| 
						 | 
				
			
			@ -1,13 +1,17 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class AboutController < ApplicationController
 | 
			
		||||
  include RegistrationSpamConcern
 | 
			
		||||
 | 
			
		||||
  before_action :set_pack
 | 
			
		||||
 | 
			
		||||
  layout 'public'
 | 
			
		||||
 | 
			
		||||
  before_action :require_open_federation!, only: [:show, :more]
 | 
			
		||||
  before_action :set_body_classes, only: :show
 | 
			
		||||
  before_action :set_instance_presenter
 | 
			
		||||
  before_action :set_expires_in, only: [:show, :more, :terms]
 | 
			
		||||
  before_action :set_expires_in, only: [:more, :terms]
 | 
			
		||||
  before_action :set_registration_form_time, only: :show
 | 
			
		||||
 | 
			
		||||
  skip_before_action :require_functional!, only: [:more, :terms]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
class Auth::RegistrationsController < Devise::RegistrationsController
 | 
			
		||||
  include Devise::Controllers::Rememberable
 | 
			
		||||
  include RegistrationSpamConcern
 | 
			
		||||
 | 
			
		||||
  layout :determine_layout
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
 | 
			
		|||
  before_action :set_body_classes, only: [:new, :create, :edit, :update]
 | 
			
		||||
  before_action :require_not_suspended!, only: [:update]
 | 
			
		||||
  before_action :set_cache_headers, only: [:edit, :update]
 | 
			
		||||
  before_action :set_registration_form_time, only: :new
 | 
			
		||||
 | 
			
		||||
  skip_before_action :require_functional!, only: [:edit, :update]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,6 +50,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
 | 
			
		|||
 | 
			
		||||
    resource.locale                 = I18n.locale
 | 
			
		||||
    resource.invite_code            = params[:invite_code] if resource.invite_code.blank?
 | 
			
		||||
    resource.registration_form_time = session[:registration_form_time]
 | 
			
		||||
    resource.sign_up_ip             = request.remote_ip
 | 
			
		||||
 | 
			
		||||
    resource.build_account if resource.account.nil?
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +58,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
 | 
			
		|||
 | 
			
		||||
  def configure_sign_up_params
 | 
			
		||||
    devise_parameter_sanitizer.permit(:sign_up) do |u|
 | 
			
		||||
      u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement)
 | 
			
		||||
      u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement, :website, :confirm_password)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module RegistrationSpamConcern
 | 
			
		||||
  extend ActiveSupport::Concern
 | 
			
		||||
 | 
			
		||||
  def set_registration_form_time
 | 
			
		||||
    session[:registration_form_time] = Time.now.utc
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -32,10 +32,16 @@ const messages = defineMessages({
 | 
			
		|||
  markAsRead : { id: 'notifications.mark_as_read', defaultMessage: 'Mark every notification as read' },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const getExcludedTypes = createSelector([
 | 
			
		||||
  state => state.getIn(['settings', 'notifications', 'shows']),
 | 
			
		||||
], (shows) => {
 | 
			
		||||
  return ImmutableList(shows.filter(item => !item).keys());
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const getNotifications = createSelector([
 | 
			
		||||
  state => state.getIn(['settings', 'notifications', 'quickFilter', 'show']),
 | 
			
		||||
  state => state.getIn(['settings', 'notifications', 'quickFilter', 'active']),
 | 
			
		||||
  state => ImmutableList(state.getIn(['settings', 'notifications', 'shows']).filter(item => !item).keys()),
 | 
			
		||||
  getExcludedTypes,
 | 
			
		||||
  state => state.getIn(['notifications', 'items']),
 | 
			
		||||
], (showFilterBar, allowedType, excludedTypes, notifications) => {
 | 
			
		||||
  if (!showFilterBar || allowedType === 'all') {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,6 +155,17 @@ function main() {
 | 
			
		|||
      target.style.display = 'block';
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // Empty the honeypot fields in JS in case something like an extension
 | 
			
		||||
  // automatically filled them.
 | 
			
		||||
  delegate(document, '#registration_new_user,#new_user', 'submit', () => {
 | 
			
		||||
    ['user_website', 'user_confirm_password', 'registration_user_website', 'registration_user_confirm_password'].forEach(id => {
 | 
			
		||||
      const field = document.getElementById(id);
 | 
			
		||||
      if (field) {
 | 
			
		||||
        field.value = '';
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
loadPolyfills()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -354,6 +354,7 @@ code {
 | 
			
		|||
  input[type=number],
 | 
			
		||||
  input[type=email],
 | 
			
		||||
  input[type=password],
 | 
			
		||||
  input[type=url],
 | 
			
		||||
  textarea {
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
| 
						 | 
				
			
			@ -994,3 +995,10 @@ code {
 | 
			
		|||
    flex-direction: row;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.input.user_confirm_password,
 | 
			
		||||
.input.user_website {
 | 
			
		||||
  &:not(.field_with_errors) {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,6 +89,13 @@ class User < ApplicationRecord
 | 
			
		|||
  validates_with EmailMxValidator, if: :validate_email_dns?
 | 
			
		||||
  validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
 | 
			
		||||
 | 
			
		||||
  # Those are honeypot/antispam fields
 | 
			
		||||
  attr_accessor :registration_form_time, :website, :confirm_password
 | 
			
		||||
 | 
			
		||||
  validates_with RegistrationFormTimeValidator, on: :create
 | 
			
		||||
  validates :website, absence: true, on: :create
 | 
			
		||||
  validates :confirm_password, absence: true, on: :create
 | 
			
		||||
 | 
			
		||||
  scope :recent, -> { order(id: :desc) }
 | 
			
		||||
  scope :pending, -> { where(approved: false) }
 | 
			
		||||
  scope :approved, -> { where(approved: true) }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class RegistrationFormTimeValidator < ActiveModel::Validator
 | 
			
		||||
  REGISTRATION_FORM_MIN_TIME = 3.seconds.freeze
 | 
			
		||||
 | 
			
		||||
  def validate(user)
 | 
			
		||||
    user.errors.add(:base, I18n.t('auth.too_fast')) if user.registration_form_time.present? && user.registration_form_time > REGISTRATION_FORM_MIN_TIME.ago
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +10,9 @@
 | 
			
		|||
      = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'off', :minlength => User.password_length.first, :maxlength => User.password_length.last }, hint: false, disabled: closed_registrations?
 | 
			
		||||
      = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?
 | 
			
		||||
 | 
			
		||||
      = f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?
 | 
			
		||||
      = f.input :website, as: :url, placeholder: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: 'Website'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?
 | 
			
		||||
 | 
			
		||||
    - if approved_registrations?
 | 
			
		||||
      .fields-group
 | 
			
		||||
        = f.simple_fields_for :invite_request do |invite_request_fields|
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,9 @@
 | 
			
		|||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'off' }
 | 
			
		||||
    = f.input :confirm_password, as: :string, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), :autocomplete => 'off' }
 | 
			
		||||
 | 
			
		||||
  = f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: 'Website'), :autocomplete => 'off' }
 | 
			
		||||
 | 
			
		||||
  - if approved_registrations? && !@invite.present?
 | 
			
		||||
    .fields-group
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,6 @@
 | 
			
		|||
- if object.errors.any?
 | 
			
		||||
  .flash-message.alert#error_explanation
 | 
			
		||||
    %strong= t('generic.validation_errors', count: object.errors.count)
 | 
			
		||||
- object.errors[:base].each do |error|
 | 
			
		||||
  .flash-message.alert
 | 
			
		||||
    %strong= error
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -751,6 +751,7 @@ en:
 | 
			
		|||
      functional: Your account is fully operational.
 | 
			
		||||
      pending: Your application is pending review by our staff. This may take some time. You will receive an e-mail if your application is approved.
 | 
			
		||||
      redirecting_to: Your account is inactive because it is currently redirecting to %{acct}.
 | 
			
		||||
    too_fast: Form submitted too fast, try again.
 | 
			
		||||
    trouble_logging_in: Trouble logging in?
 | 
			
		||||
    use_security_key: Use security key
 | 
			
		||||
  authorize_follow:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -126,6 +126,7 @@ en:
 | 
			
		|||
        expires_in: Expire after
 | 
			
		||||
        fields: Profile metadata
 | 
			
		||||
        header: Header
 | 
			
		||||
        honeypot: "%{label} (do not fill in)"
 | 
			
		||||
        inbox_url: URL of the relay inbox
 | 
			
		||||
        irreversible: Drop instead of hide
 | 
			
		||||
        locale: Interface language
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,6 +82,10 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
 | 
			
		|||
  describe 'POST #create' do
 | 
			
		||||
    let(:accept_language) { Rails.application.config.i18n.available_locales.sample.to_s }
 | 
			
		||||
 | 
			
		||||
    before do
 | 
			
		||||
      session[:registration_form_time] = 5.seconds.ago
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    around do |example|
 | 
			
		||||
      current_locale = I18n.locale
 | 
			
		||||
      example.run
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue