forked from fedi/mastodon
3511528e50
When deduplicating account usernames for OAuthable users, the routine did check if any account was known with that username, including remote accounts. This caused some unnecessary deduplication, and usernames ending with unexpected trailing _1. This fixes #13580
94 lines
2.8 KiB
Ruby
94 lines
2.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Omniauthable
|
|
extend ActiveSupport::Concern
|
|
|
|
TEMP_EMAIL_PREFIX = 'change@me'
|
|
TEMP_EMAIL_REGEX = /\A#{TEMP_EMAIL_PREFIX}/.freeze
|
|
|
|
included do
|
|
devise :omniauthable
|
|
|
|
def omniauth_providers
|
|
Devise.omniauth_configs.keys
|
|
end
|
|
|
|
def email_verified?
|
|
email && email !~ TEMP_EMAIL_REGEX
|
|
end
|
|
end
|
|
|
|
class_methods do
|
|
def find_for_oauth(auth, signed_in_resource = nil)
|
|
# EOLE-SSO Patch
|
|
auth.uid = (auth.uid[0][:uid] || auth.uid[0][:user]) if auth.uid.is_a? Hashie::Array
|
|
identity = Identity.find_for_oauth(auth)
|
|
|
|
# If a signed_in_resource is provided it always overrides the existing user
|
|
# to prevent the identity being locked with accidentally created accounts.
|
|
# Note that this may leave zombie accounts (with no associated identity) which
|
|
# can be cleaned up at a later date.
|
|
user = signed_in_resource || identity.user
|
|
user ||= create_for_oauth(auth)
|
|
|
|
if identity.user.nil?
|
|
identity.user = user
|
|
identity.save!
|
|
end
|
|
|
|
user
|
|
end
|
|
|
|
def create_for_oauth(auth)
|
|
# Check if the user exists with provided email if the provider gives us a
|
|
# verified email. If no verified email was provided or the user already
|
|
# exists, we assign a temporary email and ask the user to verify it on
|
|
# the next step via Auth::SetupController.show
|
|
|
|
strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
|
|
assume_verified = strategy&.security&.assume_email_is_verified
|
|
email_is_verified = auth.info.verified || auth.info.verified_email || assume_verified
|
|
email = auth.info.verified_email || auth.info.email
|
|
email = nil unless email_is_verified
|
|
|
|
user = User.find_by(email: email) if email_is_verified
|
|
|
|
return user unless user.nil?
|
|
|
|
user = User.new(user_params_from_auth(email, auth))
|
|
|
|
user.account.avatar_remote_url = auth.info.image if auth.info.image =~ /\A#{URI.regexp(%w(http https))}\z/
|
|
user.skip_confirmation!
|
|
user.save!
|
|
user
|
|
end
|
|
|
|
private
|
|
|
|
def user_params_from_auth(email, auth)
|
|
{
|
|
email: email || "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",
|
|
password: Devise.friendly_token[0, 20],
|
|
agreement: true,
|
|
external: true,
|
|
account_attributes: {
|
|
username: ensure_unique_username(auth.uid),
|
|
display_name: auth.info.full_name || [auth.info.first_name, auth.info.last_name].join(' '),
|
|
},
|
|
}
|
|
end
|
|
|
|
def ensure_unique_username(starting_username)
|
|
username = starting_username
|
|
i = 0
|
|
|
|
while Account.exists?(username: username, domain: nil)
|
|
i += 1
|
|
username = "#{starting_username}_#{i}"
|
|
end
|
|
|
|
username
|
|
end
|
|
end
|
|
end
|