]> git.openstreetmap.org Git - rails.git/blob - app/controllers/users_controller.rb
Convert `UserMailer#email_confirm` to new style
[rails.git] / app / controllers / users_controller.rb
1 # frozen_string_literal: true
2
3 class UsersController < ApplicationController
4   include EmailMethods
5   include SessionMethods
6   include UserMethods
7
8   layout :site_layout
9
10   skip_before_action :verify_authenticity_token, :only => [:auth_success]
11   before_action :authorize_web
12   before_action :set_locale
13   before_action :check_database_readable
14
15   authorize_resource
16
17   before_action :check_database_writable, :only => [:new, :go_public]
18   before_action :require_cookies, :only => [:new]
19
20   allow_thirdparty_images :only => :show
21   allow_social_login :only => :new
22
23   def show
24     @user = User.find_by(:display_name => params[:display_name])
25
26     if @user && (@user.visible? || current_user&.administrator?)
27       @title = @user.display_name
28       @heatmap_frame = @user.public_heatmap?
29     else
30       render_unknown_user params[:display_name]
31     end
32   end
33
34   def new
35     @title = t ".title"
36     @referer = safe_referer(params[:referer])
37
38     parse_oauth_referer @referer
39
40     if current_user
41       # The user is logged in already, so don't show them the signup
42       # page, instead send them to the home page
43       redirect_to @referer || { :controller => "site", :action => "index" }
44     elsif params.key?(:auth_provider) && params.key?(:auth_uid)
45       @email_hmac = params[:email_hmac]
46
47       self.current_user = User.new(:email => params[:email],
48                                    :display_name => params[:nickname],
49                                    :auth_provider => params[:auth_provider],
50                                    :auth_uid => params[:auth_uid])
51
52       if current_user.valid? || current_user.errors[:email].empty?
53         flash.now[:notice] = render_to_string :partial => "auth_association"
54       else
55         flash.now[:warning] = t ".duplicate_social_email"
56       end
57     elsif check_signup_allowed?
58       self.current_user = User.new
59     else
60       render :action => "blocked"
61     end
62   end
63
64   def create
65     self.current_user = User.new(user_params)
66
67     if check_signup_allowed?(current_user.email)
68       if current_user.auth_uid.present?
69         # We are creating an account with external authentication and
70         # no password was specified so create a random one
71         current_user.pass_crypt = SecureRandom.base64(16)
72         current_user.pass_crypt_confirmation = current_user.pass_crypt
73       end
74
75       if current_user.invalid?
76         # Something is wrong with a new user, so rerender the form
77         render :action => "new"
78       else
79         # Save the user record
80         if save_new_user params[:email_hmac]
81           SIGNUP_IP_LIMITER&.update(request.remote_ip)
82           SIGNUP_EMAIL_LIMITER&.update(canonical_email(current_user.email))
83
84           flash[:matomo_goal] = Settings.matomo["goals"]["signup"] if defined?(Settings.matomo)
85
86           referer = welcome_path(welcome_options(params[:referer]))
87
88           if current_user.status == "active"
89             successful_login(current_user, referer)
90           else
91             session[:pending_user] = current_user.id
92             UserMailer.with(
93               :user => current_user,
94               :token => current_user.generate_token_for(:new_user),
95               :referer => referer
96             ).signup_confirm.deliver_later
97             redirect_to :controller => :confirmations, :action => :confirm, :display_name => current_user.display_name
98           end
99         else
100           render :action => "new", :referer => params[:referer]
101         end
102       end
103     else
104       render :action => "blocked"
105     end
106   end
107
108   def go_public
109     current_user.data_public = true
110     current_user.save
111     flash[:notice] = t ".flash success"
112     redirect_to account_path
113   end
114
115   ##
116   # omniauth success callback
117   def auth_success
118     referer = request.env["omniauth.params"]["referer"]
119     auth_info = request.env["omniauth.auth"]
120
121     provider = auth_info[:provider]
122     uid = auth_info[:uid]
123     name = auth_info[:info][:name]
124     email = auth_info[:info][:email]
125
126     email_verified = case provider
127                      when "google", "apple", "facebook", "microsoft", "github", "wikipedia"
128                        true
129                      else
130                        false
131                      end
132
133     if settings = session.delete(:new_user_settings)
134       current_user.auth_provider = provider
135       current_user.auth_uid = uid
136
137       update_user(current_user, settings)
138
139       flash.discard
140
141       session[:user_errors] = current_user.errors.as_json
142
143       redirect_to account_path
144     else
145       user = User.find_by(:auth_provider => provider, :auth_uid => uid)
146
147       if user.nil? && provider == "google"
148         openid_url = auth_info[:extra][:id_info]["openid_id"]
149         user = User.find_by(:auth_provider => "openid", :auth_uid => openid_url) if openid_url
150         user&.update(:auth_provider => provider, :auth_uid => uid)
151       end
152
153       if user
154         case user.status
155         when "pending"
156           unconfirmed_login(user, referer)
157         when "active", "confirmed"
158           successful_login(user, referer)
159         when "suspended"
160           failed_login({ :partial => "sessions/suspended_flash" }, user.display_name, referer)
161         else
162           failed_login(t("sessions.new.auth failure"), user.display_name, referer)
163         end
164       else
165         email_hmac = UsersController.message_hmac(email) if email_verified && email
166         redirect_to :action => "new", :nickname => name, :email => email, :email_hmac => email_hmac,
167                     :auth_provider => provider, :auth_uid => uid, :referer => referer
168       end
169     end
170   end
171
172   ##
173   # omniauth failure callback
174   def auth_failure
175     flash[:error] = t(params[:message], :scope => "users.auth_failure", :default => t(".unknown_error"))
176
177     origin = safe_referer(params[:origin]) if params[:origin]
178
179     redirect_to origin || login_url
180   end
181
182   def self.message_hmac(text)
183     sha256 = Digest::SHA256.new
184     sha256 << Rails.application.key_generator.generate_key("openstreetmap/email_address")
185     sha256 << text
186     Base64.urlsafe_encode64(sha256.digest)
187   end
188
189   private
190
191   def save_new_user(email_hmac)
192     current_user.data_public = true
193     current_user.description = "" if current_user.description.nil?
194     current_user.creation_address = request.remote_ip
195     current_user.languages = if request.cookies["_osm_locale"]
196                                Locale.list(request.cookies["_osm_locale"])
197                              else
198                                http_accept_language.user_preferred_languages
199                              end
200     current_user.terms_agreed = Time.now.utc
201     current_user.tou_agreed = Time.now.utc
202     current_user.terms_seen = true
203
204     if current_user.auth_uid.blank?
205       current_user.auth_provider = nil
206       current_user.auth_uid = nil
207     elsif email_hmac && ActiveSupport::SecurityUtils.secure_compare(email_hmac, UsersController.message_hmac(current_user.email))
208       current_user.activate
209     end
210
211     current_user.save
212   end
213
214   def welcome_options(referer = nil)
215     uri = URI(referer) if referer.present?
216
217     return { "oauth_return_url" => uri&.to_s } if uri&.path == oauth_authorization_path
218
219     begin
220       %r{map=(.*)/(.*)/(.*)}.match(uri.fragment) do |m|
221         editor = Rack::Utils.parse_query(uri.query).slice("editor")
222         return { "zoom" => m[1], "lat" => m[2], "lon" => m[3] }.merge(editor)
223       end
224     rescue StandardError
225       # Use default
226     end
227   end
228
229   ##
230   # return permitted user parameters
231   def user_params
232     params.expect(:user => [:email, :display_name,
233                             :auth_provider, :auth_uid,
234                             :pass_crypt, :pass_crypt_confirmation])
235   end
236
237   ##
238   # check signup acls
239   def check_signup_allowed?(email = nil)
240     domain = if email.nil?
241                nil
242              else
243                email.split("@").last
244              end
245
246     mx_servers = if domain.nil?
247                    nil
248                  else
249                    domain_mx_servers(domain)
250                  end
251
252     return true if Acl.allow_account_creation?(request.remote_ip, :domain => domain, :mx => mx_servers)
253
254     blocked = Acl.no_account_creation?(request.remote_ip, :domain => domain, :mx => mx_servers)
255
256     blocked ||= SIGNUP_IP_LIMITER && !SIGNUP_IP_LIMITER.allow?(request.remote_ip)
257
258     blocked ||= email && SIGNUP_EMAIL_LIMITER && !SIGNUP_EMAIL_LIMITER.allow?(canonical_email(email))
259
260     logger.info "Blocked signup from #{request.remote_ip} for #{email}" if blocked
261
262     !blocked
263   end
264 end