Module: Auth::Concerns::OtpConcern
- Extended by:
- ActiveSupport::Concern
- Defined in:
- app/controllers/auth/concerns/otp_concern.rb
Instance Method Summary collapse
- #initialize_vars ⇒ Object
-
#otp_verification_result ⇒ Object
SHORT-POLLING ENDPOINT TO DETERMINE IF THE OTP WAS VALID.
- #permitted_params ⇒ Object
-
#resend_sms_otp ⇒ Object
this is only used for the modal based things has no role otherwise.
-
#send_sms_otp ⇒ Object
CALLED WHEN THE USER HAS ENTERED HIS MOBILE NUMBER, SO THAT HE GETS ANOTHER OTP.
-
#verify_otp ⇒ Object
CALLED WHEN THE USER ENTERS THE OTP SENT ON HIS MOBILE VERIFIES THE OTP WITH THE THIRD PARTY API.
Instance Method Details
#initialize_vars ⇒ Object
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'app/controllers/auth/concerns/otp_concern.rb', line 13 def initialize_vars ##deep symbolize the incoming params after passing through permitted params. @resource_params = permitted_params puts "the resoure params are:" puts @resource_params.to_s ##if the resource is defined, assign the class and the symbol for use further in the file ##eg: resource is provided in the route as : users, so ##@resource_class => User ##@resource_symbol => :user if collection = @resource_params[:resource] ##check that the resource exists in the auth_configuration if Auth.configuration.auth_resources[collection.singularize.capitalize] @resource_class = collection.singularize.capitalize.constantize @resource_symbol = collection.singularize.to_sym ##this is either the provided email(in case of forgot_password form, we pass in the additional_login_param under the email key itself.#ref auth/modals/forgot_password_content.html.erb) if @resource_params[@resource_symbol] @additional_login_param = @resource_params[@resource_symbol][:email] || @resource_params[@resource_symbol][:additional_login_param] ##the otp provided by the user, only used in the verify_otp action. @otp = @resource_params[@resource_symbol][:otp] ##the resource_id of the user, only used in the short_polling endpoint. @resource_id = @resource_params[@resource_symbol][:_id] end else ##have to have some way of showing these errors. not_found("provided resource not found in app") end else not_found("no resource collection provided") end ##the intent , passed into the send_sms_otp endpoint, and thereafter added to the verify_otp_path, in the new_otp_input.html.erb ##set as default to empty so that it doesnt screw up in the partials, screaming undefined. @intent = @resource_params[:intent] or "" ##the default response status, can be changed in the action depending on individual situations. @response_status = 200 end |
#otp_verification_result ⇒ Object
SHORT-POLLING ENDPOINT TO DETERMINE IF THE OTP WAS VALID. CALLED IN THE POST-VERIFICATION PAGE. error returns for this def are different, because it is requested using json from the verify_otp.js.erb partial as a result, in case there is an error in the controller action itslef below(eg. wherever there is a 422/400), then the following happens. spinner.js //catches any non 200/201 status and interprets it as an error //thereafter directly show_error_modal is called. //i could have written logic specific for otp_verification_result, by checking if it is there in the request_url, but did not do so, because otp is not always going to be in the engine, so otp should not be hardcoded anywhere. //the error lands up being shown inside show_error_modal, by means of json parsing the incoming string, and showing json as the error message. on the other hand, if there is any othe rtype of error in the before_filter initialize_vars, then that raises a not_found and is handled by rendering a json response with errors, and a 422 so again it is handled by spinner as above.
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'app/controllers/auth/concerns/otp_concern.rb', line 147 def otp_verification_result ## a message to display on the website after the otp is successfully verified in case of forgot_password or unlock_account. = nil res_verified = false ##first check the errors if resource = @resource_class.where(:additional_login_param => @additional_login_param, :otp => @otp).first if otp_error = resource.check_otp_errors @status = 422 resource.errors.add(:additional_login_param,otp_error) else resource.m_client = self.m_client resource.set_client_authentication if resource.additional_login_param_confirmed? puts "resource additional login param is confirmed." puts "intent is: #{@intent}" if @intent == "reset_password" ##protected method so had to do this. if resource.confirmed? && !resource.pending_reconfirmation? resource.class.send_reset_password_instructions(resource.attributes) = "An email has been sent to your email account, with instructions on resetting your password" if resource.errors.empty? ##if successfull_sent -> ##else ## here error is added anyway to resource. ##end ##we want to send the reset password instructions, but using the email. else resource.errors.add(:additional_login_param,"you do not have a confirmed email account set for this account, you cannot recover the password.") @status = 400 end #raw_token = resource.send(:set_reset_password_token) #intent_url = send("edit_#{@resource_symbol.to_s}_password_path",{:reset_password_token => raw_token}) elsif @intent == "unlock_account" ##here normally would be resource.unlock. ##code from https://github.com/plataformatec/devise/blob/master/lib/devise/models/lockable.rb#send_unlock_instructions #puts "came to unlocks." #raw, enc = Devise.token_generator.generate(@resource.class, :unlock_token) #@resource.unlock_token = enc #@resource.save(validate: false) if resource.confirmed? && !resource. pending_reconfirmation? resource.send_unlock_instructions = "An email has been sent to your email account, with instructions on unlocking your account" if resource.errors.empty? else resource.errors.add(:additional_login_param,"cannot send unlock instructions because you dont have a confirmed email address.") end #intent_url = send("#{@resource_symbol.to_s}_unlock_path",{:unlock_token => raw}) end ##make the intent token nil, it can be used only thus once. end end else resource = @resource_class.new @status = 422 puts "came here." resource.errors.add(:additional_login_param,"Either otp or additional login param is incorrect, try resend otp") end #puts @resource.attributes.to_s @auth_user = resource respond_to do |format| format.json {render json: {:intent_verification_message => , :errors => resource.errors., :resource => resource.as_json({:otp_verification => true}), :verified => (resource.additional_login_param_confirmed? && resource.errors.empty?)}, status: @status} format.html {render "auth/confirmations/otp_status_result.html.erb"} end end |
#permitted_params ⇒ Object
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'app/controllers/auth/concerns/otp_concern.rb', line 235 def permitted_params if action_name == "resend_sms_otp" ##the resource_collection_path => pluralized downcased model name eg. users params.permit(:intent,:resource,:api_key,:current_app_id) else ##post_verification_intent => "reset_password" OR "unlock" ##had to add email here because in the passwords form, and the unlocks form, we have to serve either additional_login_param or email, so in order to make it work with the existing devise controllers decided to keep the param coming in as email, and sending errors back also on the email attribute,[all this is only relevant to the send_sms_otp action] ##it will take all the models provided in the authentication_keys in the Auth configuration file. filters = [] Auth.configuration.auth_resources.keys.each do |model| filters << {model.downcase.to_sym => [:additional_login_param, :otp, :email, :_id]} end filters << [:intent, :resource,:api_key,:current_app_id] filters << "g-recaptcha-response".to_sym params.permit(filters) end end |
#resend_sms_otp ⇒ Object
this is only used for the modal based things has no role otherwise. CALLED WHEN WE WANT TO SHOW THE USER A MODAL TO RE-ENTER HIS MOBILE NUMBER SO THAT WE CAN AGAIN SEND AN OTP TO IT.
99 100 101 102 103 104 105 |
# File 'app/controllers/auth/concerns/otp_concern.rb', line 99 def resend_sms_otp resource = @resource_class.new respond_to do |format| format.json {render json: resource.to_json, status: @status} format.js {render "auth/confirmations/_resend_otp.js.erb", locals: {resource: resource, intent: @intent}} end end |
#send_sms_otp ⇒ Object
CALLED WHEN THE USER HAS ENTERED HIS MOBILE NUMBER, SO THAT HE GETS ANOTHER OTP
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'app/controllers/auth/concerns/otp_concern.rb', line 65 def send_sms_otp ##IF THERE IS AN INTENT,THEN WE MUST HAVE A CONFIRMED ACCOUNT. ##OTHERWISE WE DONT NEED THAT. ##WHY? ##because : suppose that we are calling send_sms_otp from the forgot_password / unlocks controller -> then we have to ensure that the account has been verified. ##otherwise we cannot send otp's to non-verified phone numbers to do things like reset_passwords / unlock ##on the other hand in case there is no intent, like in case of resend_otp -> then we can only check if we have an account with this mobile number or not, no need to check for verification. conditions = @intent.blank? ? {:additional_login_param => @additional_login_param} : {:additional_login_param => @additional_login_param, :additional_login_param_status => 2} if @additional_login_param.nil? @status = 422 resource = @resource_class.new resource.errors.add(:additional_login_param,"Additional login param not provided") elsif resource = @resource_class.where(conditions).first #resource.intent_token = Devise.friendly_token if [email protected]? #resource.save resource.m_client = self.m_client resource.set_client_authentication resource.send_sms_otp elsif resource = @resource_class.new @status = 422 resource.errors.add(:additional_login_param,"Could not find a resource with that additional login param") end @auth_user = resource respond_to do |format| format.json {render json: resource.to_json({:otp_verification => true}), status: @status} format.js {render :partial => "auth/confirmations/new_otp_input.js.erb", locals: {resource: resource, intent: @intent}} format.html {render 'auth/confirmations/enter_otp.html.erb'} end end |
#verify_otp ⇒ Object
CALLED WHEN THE USER ENTERS THE OTP SENT ON HIS MOBILE VERIFIES THE OTP WITH THE THIRD PARTY API.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'app/controllers/auth/concerns/otp_concern.rb', line 109 def verify_otp if resource = @resource_class.where(:additional_login_param => @additional_login_param).first resource.m_client = self.m_client resource.set_client_authentication ##there are no errors, so we proceed with verification. if otp_error = resource.check_otp_errors @status = 422 resource.errors.add(:additional_login_param,otp_error) else resource.verify_sms_otp(@otp) ## just setting so that it is available on the resource object. resource.otp = @otp end else resource = @resource_class.new resource.errors.add(:additional_login_param,"Not Found") @status = 400 end @auth_user = resource respond_to do |format| format.json {render json: resource.as_json({:otp_verification => true}), status: @status} format.js {render :partial => "auth/confirmations/verify_otp.js.erb", locals: {resource: resource, intent: @intent, otp: @otp}} format.html {render "auth/confirmations/get_otp_status.html.erb"} end end |