]> cat aescling's git repositories - mastodon.git/blob - app/models/concerns/omniauthable.rb
Fix SSO login not using existing account when e-mail is verified (#11862)
[mastodon.git] / app / models / concerns / omniauthable.rb
1 # frozen_string_literal: true
2
3 module Omniauthable
4 extend ActiveSupport::Concern
5
6 TEMP_EMAIL_PREFIX = 'change@me'
7 TEMP_EMAIL_REGEX = /\A#{TEMP_EMAIL_PREFIX}/.freeze
8
9 included do
10 devise :omniauthable
11
12 def omniauth_providers
13 Devise.omniauth_configs.keys
14 end
15
16 def email_verified?
17 email && email !~ TEMP_EMAIL_REGEX
18 end
19 end
20
21 class_methods do
22 def find_for_oauth(auth, signed_in_resource = nil)
23 # EOLE-SSO Patch
24 auth.uid = (auth.uid[0][:uid] || auth.uid[0][:user]) if auth.uid.is_a? Hashie::Array
25 identity = Identity.find_for_oauth(auth)
26
27 # If a signed_in_resource is provided it always overrides the existing user
28 # to prevent the identity being locked with accidentally created accounts.
29 # Note that this may leave zombie accounts (with no associated identity) which
30 # can be cleaned up at a later date.
31 user = signed_in_resource || identity.user
32 user ||= create_for_oauth(auth)
33
34 if identity.user.nil?
35 identity.user = user
36 identity.save!
37 end
38
39 user
40 end
41
42 def create_for_oauth(auth)
43 # Check if the user exists with provided email if the provider gives us a
44 # verified email. If no verified email was provided or the user already
45 # exists, we assign a temporary email and ask the user to verify it on
46 # the next step via Auth::SetupController.show
47
48 strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
49 assume_verified = strategy&.security&.assume_email_is_verified
50 email_is_verified = auth.info.verified || auth.info.verified_email || assume_verified
51 email = auth.info.verified_email || auth.info.email
52 email = nil unless email_is_verified
53
54 user = User.find_by(email: email) if email_is_verified
55
56 return user unless user.nil?
57
58 user = User.new(user_params_from_auth(email, auth))
59
60 user.account.avatar_remote_url = auth.info.image if auth.info.image =~ /\A#{URI.regexp(%w(http https))}\z/
61 user.skip_confirmation!
62 user.save!
63 user
64 end
65
66 private
67
68 def user_params_from_auth(email, auth)
69 {
70 email: email || "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",
71 password: Devise.friendly_token[0, 20],
72 agreement: true,
73 external: true,
74 account_attributes: {
75 username: ensure_unique_username(auth.uid),
76 display_name: auth.info.full_name || [auth.info.first_name, auth.info.last_name].join(' '),
77 },
78 }
79 end
80
81 def ensure_unique_username(starting_username)
82 username = starting_username
83 i = 0
84
85 while Account.exists?(username: username)
86 i += 1
87 username = "#{starting_username}_#{i}"
88 end
89
90 username
91 end
92 end
93 end
This page took 0.0676 seconds and 5 git commands to generate.