# frozen_string_literal: true module API::V2 module Identity module Utils def session request.session end def codec @_codec ||= Barong::JWT.new(key: Barong::App.config.keystore.private_key) end def open_session(user) csrf_token = SecureRandom.hex(10) session.merge!( "uid": user.uid, "user_ip": remote_ip, "user_agent": request.env['HTTP_USER_AGENT'], "expire_time": Time.now.to_i + Barong::App.config.session_expire_time, "csrf_token": csrf_token ) csrf_token end def verify_captcha!(response:, endpoint:, error_statuses: [400, 422]) # by default we protect user_create session_create password_reset email_confirmation endpoints return unless BarongConfig.list['captcha_protected_endpoints']&.include?(endpoint) case Barong::App.config.captcha when 'recaptcha' recaptcha(response: response) when 'geetest' geetest(response: response) end end def recaptcha(response:, error_statuses: [400, 422]) error!({ errors: ['identity.captcha.required'] }, error_statuses.first) if response.blank? captcha_error_message = 'identity.captcha.verification_failed' if CaptchaService::RecaptchaVerifier.new(request: request).response_valid?(skip_remote_ip: true, response: response) return end error!({ errors: [captcha_error_message] }, error_statuses.last) rescue StandardError error!({ errors: [captcha_error_message] }, error_statuses.last) end def geetest(response:, error_statuses: [400, 422]) error!({ errors: ['identity.captcha.required'] }, error_statuses.first) if response.blank? geetest_error_message = 'identity.captcha.verification_failed' validate_geetest_response(response: response) return if CaptchaService::GeetestVerifier.new.validate(response) error!({ errors: [geetest_error_message] }, error_statuses.last) rescue StandardError error!({ errors: [geetest_error_message] }, error_statuses.last) end def validate_geetest_response(response:) unless (response['geetest_challenge'].is_a? String) && (response['geetest_validate'].is_a? String) && (response['geetest_seccode'].is_a? String) error!({ errors: ['identity.captcha.mandatory_fields'] }, 400) end end def login_error!(options = {}) options[:data] = { reason: options[:reason] }.to_json options[:topic] = 'session' activity_record(options.except(:reason, :error_code, :error_text)) error!({ errors: ['identity.session.' + options[:error_text]] }, options[:error_code]) end def activity_record(options = {}) params = { category: 'user', user_id: options[:user], user_ip: remote_ip, user_agent: request.env['HTTP_USER_AGENT'], topic: options[:topic], action: options[:action], result: options[:result], data: options[:data] } Activity.create(params) end def token_uniq?(jti) error!({ errors: ['identity.user.utilized_token'] }, 422) if Rails.cache.read(jti) == 'utilized' Rails.cache.write(jti, 'utilized', expires_in: Barong::App.config.jwt_expire_time.seconds) end def publish_confirmation(user, domain) token = codec.encode(sub: 'confirmation', email: user.email, uid: user.uid) EventAPI.notify( 'system.user.email.confirmation.token', record: { user: user.as_json_for_event_api, domain: domain, token: token } ) end def publish_confirmation_code(user, domain, action) totp = TOTPServiceAction.new(action) totp.create(user.uid, user.email) record = { user: user.as_json_for_event_api, domain: domain, code: totp.read_code(user.uid) } case action when 'sign-up' record[:token] = codec.encode(sub: 'confirmation', email: user.email, uid: user.uid) when 'reset-password' reset_token = SecureRandom.hex(10) Rails.cache.write( "reset_password_#{user.email}", reset_token, expires_in: Barong::App.config.jwt_expire_time.seconds ) record[:token] = codec.encode( sub: 'reset', email: user.email, uid: user.uid, reset_token: reset_token ) end EventAPI.notify(action, record: record) end def publish_session_create(user) EventAPI.notify('system.session.create', record: { user: user.as_json_for_event_api, user_ip: remote_ip, user_agent: request.env['HTTP_USER_AGENT'] }) end def publish_session_failed(user) EventAPI.notify('system.session.failed', record: { user: user.as_json_for_event_api, user_ip: remote_ip, user_agent: request.env['HTTP_USER_AGENT'] }) end end end end