177 lines
6.9 KiB
Ruby
177 lines
6.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_dependency 'barong/jwt'
|
|
|
|
module API::V2
|
|
module Identity
|
|
class Sessions < Grape::API
|
|
helpers do
|
|
def get_user(email)
|
|
user = User.find_by(email: email)
|
|
error!({ errors: ['identity.session.invalid_params'] }, 401) unless user
|
|
|
|
if user.state == 'banned'
|
|
login_error!(reason: 'Your account is banned', error_code: 401,
|
|
user: user.id, action: 'login', result: 'failed', error_text: 'banned')
|
|
end
|
|
|
|
if user.state == 'deleted'
|
|
login_error!(reason: 'Your account is deleted', error_code: 401,
|
|
user: user.id, action: 'login', result: 'failed', error_text: 'deleted')
|
|
end
|
|
|
|
# if user is not active or pending, then return 401
|
|
unless user.state.in?(%w[active pending])
|
|
login_error!(reason: 'Your account is not active', error_code: 401,
|
|
user: user.id, action: 'login', result: 'failed', error_text: 'not_active')
|
|
end
|
|
user
|
|
end
|
|
end
|
|
|
|
desc 'Session related routes'
|
|
resource :sessions do
|
|
desc 'Start a new session for every LogIn',
|
|
failure: [
|
|
{ code: 400, message: 'Required params are empty' },
|
|
{ code: 404, message: 'Record is not found' }
|
|
]
|
|
params do
|
|
requires :email
|
|
requires :password
|
|
optional :captcha_response,
|
|
types: { value: [String, Hash], message: 'identity.session.invalid_captcha_format' },
|
|
desc: 'Response from captcha widget'
|
|
optional :otp_code,
|
|
type: String,
|
|
desc: 'Code from Google Authenticator'
|
|
end
|
|
post do
|
|
verify_captcha!(response: params['captcha_response'], endpoint: 'session_create')
|
|
|
|
declared_params = declared(params, include_missing: false)
|
|
user = get_user(declared_params[:email])
|
|
error!({ errors: ['identity.session.not_active'] }, 401) unless user.state == 'active'
|
|
|
|
unless user.authenticate(declared_params[:password])
|
|
publish_session_failed(user)
|
|
login_error!(reason: 'Invalid Email or Password', error_code: 401, user: user.id,
|
|
action: 'login', result: 'failed', error_text: 'invalid_params')
|
|
end
|
|
|
|
unless user.otp
|
|
activity_record(user: user.id, action: 'login', result: 'succeed', topic: 'session')
|
|
csrf_token = open_session(user)
|
|
publish_session_create(user)
|
|
|
|
present user, with: API::V2::Entities::UserWithFullInfo, csrf_token: csrf_token
|
|
return status 200
|
|
end
|
|
|
|
error!({ errors: ['identity.session.missing_otp'] }, 401) if declared_params[:otp_code].blank?
|
|
unless TOTPService.validate?(user.uid, declared_params[:otp_code])
|
|
login_error!(reason: 'OTP code is invalid', error_code: 403,
|
|
user: user.id, action: 'login::2fa', result: 'failed', error_text: 'invalid_otp')
|
|
end
|
|
|
|
activity_record(user: user.id, action: 'login::2fa', result: 'succeed', topic: 'session')
|
|
csrf_token = open_session(user)
|
|
publish_session_create(user)
|
|
|
|
present user, with: API::V2::Entities::UserWithFullInfo, csrf_token: csrf_token
|
|
status(200)
|
|
end
|
|
|
|
desc 'Destroy current session for LogOut',
|
|
failure: [
|
|
{ code: 400, message: 'Required params are empty' },
|
|
{ code: 404, message: 'Record is not found' }
|
|
],
|
|
success: { code: 200, message: 'Session was destroyed' }
|
|
delete do
|
|
user = User.find_by(uid: session[:uid])
|
|
error!({ errors: ['identity.session.not_found'] }, 404) unless user
|
|
|
|
activity_record(user: user.id, action: 'logout', result: 'succeed', topic: 'session')
|
|
|
|
session.destroy
|
|
status(200)
|
|
end
|
|
|
|
desc 'Auth0 authentication by id_token',
|
|
success: { code: 200, message: 'User authenticated' },
|
|
failure: [
|
|
{ code: 400, message: 'Required params are empty' },
|
|
{ code: 404, message: 'Record is not found' }
|
|
]
|
|
params do
|
|
requires :id_token,
|
|
type: String,
|
|
allow_blank: false,
|
|
desc: 'ID Token'
|
|
end
|
|
post '/auth0' do
|
|
begin
|
|
# Decode ID token to get user info
|
|
claims = Barong::Auth0::JWT.verify(params[:id_token]).first
|
|
error!({ errors: ['identity.session.auth0.invalid_params'] }, 401) unless claims.key?('email')
|
|
user = User.find_by(email: claims['email'])
|
|
|
|
# If there is no user in platform and user email verified from id_token
|
|
# system will create user
|
|
if user.blank? && claims['email_verified']
|
|
user = User.create!(email: claims['email'], state: 'active')
|
|
user.labels.create!(scope: 'private', key: 'email', value: 'verified')
|
|
elsif claims['email_verified'] == false
|
|
error!({ errors: ['identity.session.auth0.invalid_params'] }, 401) unless user
|
|
end
|
|
|
|
activity_record(user: user.id, action: 'login', result: 'succeed', topic: 'session')
|
|
csrf_token = open_session(user)
|
|
publish_session_create(user)
|
|
|
|
present user, with: API::V2::Entities::UserWithFullInfo, csrf_token: csrf_token
|
|
rescue StandardError => e
|
|
report_exception(e)
|
|
error!({ errors: ['identity.session.auth0.invalid_params'] }, 422)
|
|
end
|
|
end
|
|
|
|
desc 'Resend confirmations code(authorization code)',
|
|
success: { code: 201, message: 'Generated verification code' },
|
|
failure: [
|
|
{ code: 400, message: 'Required params are missing' },
|
|
{ code: 422, message: 'Validation errors' }
|
|
]
|
|
params do
|
|
requires :data,
|
|
type: String,
|
|
allow_blank: false,
|
|
desc: 'Account email or Telephone number'
|
|
requires :action,
|
|
type: String,
|
|
allow_blank: false,
|
|
desc: 'for what need auth code'
|
|
optional :channel,
|
|
type: String,
|
|
allow_blank: true,
|
|
default: 'email',
|
|
desc: 'channel that send in'
|
|
optional :captcha_response,
|
|
types: [String, Hash],
|
|
desc: 'Response from captcha widget'
|
|
end
|
|
post '/resend' do
|
|
current_user = User.find_by_email(params[:data])
|
|
|
|
return status 201 if current_user.nil?
|
|
|
|
publish_confirmation_code(current_user, Barong::App.config.domain, params[:action])
|
|
|
|
status 201
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|