# frozen_string_literal: true module API::V2 module Resource # TOTP functionality API class Otp < Grape::API helpers do def otp_error!(options = {}) options[:topic] = 'otp' record_error!(options) end end resource :otp do desc 'Generate qr code for 2FA (first step for enabling)', failure: [ { code: 400, message: '2FA has been enabled for this account' }, { code: 401, message: 'Invalid bearer token' } ], success: { code: 200, message: 'QR code was generated' } post '/generate_qrcode' do if current_user.otp otp_error!(reason: '2FA has been already enabled for this account', error_code: 400, user: current_user.id, action: 'request QR code for 2FA', error_text: 'already_enabled') end if current_user.read_cache('enable_otp') otp_error!(reason: '2FA has been already sent email for this account', error_code: 400, user: current_user.id, action: 'request QR code for 2FA', error_text: 'already_sent') end activity_record(user: current_user.id, action: 'request QR code for 2FA', result: 'succeed', topic: 'otp') TOTPService.create(current_user.uid, current_user.email) end desc 'enter google authenticator code and send authorization code by email(second step for enabling)', failure: [ { code: 400, message: '2FA has been enabled for this account or code is missing' }, { code: 401, message: 'Invalid bearer token' }, { code: 422, message: 'Validation errors' } ], success: { code: 200, message: '2FA was enabled' } params do requires :code, type: String, allow_blank: false, desc: 'Code from Google Authenticator' end post '/enable' do if current_user.otp otp_error!(reason: '2FA has been already enabled for this account', error_code: 400, user: current_user.id, action: 'enable 2FA', error_text: 'already_enabled') end unless TOTPService.validate?(current_user.uid, declared(params)[:code]) otp_error!(reason: 'OTP code is invalid', error_code: 422, user: current_user.id, action: 'enable 2FA', error_text: 'invalid') end if current_user.read_cache('enable_otp') otp_error!(reason: '2FA has been already sent email for this account', error_code: 400, user: current_user.id, action: 'enable 2FA', error_text: 'already_enabled') end # unless current_user.update(otp: true) # # FIXME active record validation # otp_error!(reason: current_user.errors.full_messages.to_sentence, error_code: 422, # user: current_user.id, action: 'enable 2FA') # end # current_user.labels.create(key: :otp, value: :enabled, scope: :private) unless current_user.labels.find_by(key: :otp, scope: :private) # activity_record(user: current_user.id, action: 'enable 2FA', result: 'succeed', topic: 'otp') publish_confirmation_code(current_user, Barong::App.config.domain, 'enable-otp') current_user.write_cache('enable_otp', 'true', 120) 200 end desc 'enter authorization key and enable 2fa(third step for enabling)', failure: [ { code: 400, message: '2FA has been enabled for this account or code is missing' }, { code: 401, message: 'Invalid bearer token' }, { code: 422, message: 'Validation errors' } ], success: { code: 200, message: '2FA was enabled' } params do requires :code, type: String, allow_blank: false, desc: 'Code from email' end post '/enable_2fa' do if current_user.otp otp_error!(reason: '2FA has been already enabled for this account', error_code: 400, user: current_user.id, action: 'enable 2FA', error_text: 'already_enabled') end unless current_user.read_cache("enable_otp") otp_error!(reason: '2FA hasnt been enable', error_code: 400, user: current_user.id, action: 'enable 2FA', error_text: 'doesnt get email') end unless TOTPServiceAction.new('enable-otp').validate?(current_user.uid, declared(params)[:code]) otp_error!(reason: 'OTP code is invalid', error_code: 422, user: current_user.id, action: 'enable 2FA', error_text: 'invalid') end unless current_user.update(otp: true) # FIXME active record validation otp_error!(reason: current_user.errors.full_messages.to_sentence, error_code: 422, user: current_user.id, action: 'enable 2FA') end current_user.labels.create(key: :otp, value: :enabled, scope: :private) unless current_user.labels.find_by(key: :otp, scope: :private) activity_record(user: current_user.id, action: 'enable 2FA', result: 'succeed', topic: 'otp') # publish_confirmation_code(current_user,Barong::App.config.domain, action) current_user.delete_cache("enable_otp") 200 end desc 'Disable 2FA request and send authorization code(first step disabling)', failure: [ { code: 400, message: '2FA has not been enabled for this account or code is missing' }, { code: 401, message: 'Invalid bearer token' }, { code: 422, message: 'Validation errors' } ], success: { code: 200, message: '2FA was disabled' } params do requires :code, type: String, allow_blank: false, desc: 'Code from Google Authenticator' end post '/disable' do unless current_user.otp otp_error!(reason: '2FA has not been enabled for this account', error_code: 400, user: current_user.id, action: 'disable 2FA', error_text: 'not_enabled') end unless TOTPService.validate?(current_user.uid, declared(params)[:code]) otp_error!(reason: 'OTP code is invalid', error_code: 422, user: current_user.id, action: 'disable 2FA', error_text: 'invalid') end publish_confirmation_code(current_user, Barong::App.config.domain, 'disable-otp') current_user.write_cache('disable_otp', 'true', 120) status 200 end desc 'enter authorization code that send by email (second step for disabling 2FA)', failure: [ { code: 400, message: '2FA has been enabled for this account or code is missing' }, { code: 401, message: 'Invalid bearer token' }, { code: 422, message: 'Validation errors' } ], success: { code: 200, message: '2FA was disabled' } params do requires :code, type: String, allow_blank: false, desc: 'Code from Google Authenticator' end post '/disable_email' do unless current_user.otp otp_error!(reason: '2FA has not been enabled for this account', error_code: 400, user: current_user.id, action: 'disable 2FA', error_text: 'not_enabled') end unless current_user.read_cache("disable_otp") otp_error!(reason: '2FA hasnt been disable', error_code: 400, user: current_user.id, action: 'enable 2FA', error_text: 'doesnt get email') end unless TOTPServiceAction.new('disable-otp').validate?(current_user.uid, declared(params)[:code]) otp_error!(reason: 'OTP code is invalid', error_code: 422, user: current_user.id, action: 'enable 2FA', error_text: 'invalid') end unless current_user.update(otp: false) otp_error!(reason: current_user.errors.full_messages.to_sentence, error_code: 422, user: current_user.id, action: 'disable 2FA') end current_user.labels.find_by(key: :otp, scope: :private).delete if current_user.labels.find_by(key: :otp, scope: :private) activity_record(user: current_user.id, action: 'disable 2FA', result: 'succeed', topic: 'otp') status 200 end desc 'Verify 2FA code(for checking 2fa)', failure: [ { code: 400, message: '2FA has not been enabled for this account or code is missing' }, { code: 401, message: 'Invalid bearer token' }, { code: 422, message: 'Validation errors' } ], success: { code: 200, message: '2FA was verified' } params do requires :code, type: String, allow_blank: false, desc: 'Code from Google Authenticator' end post '/verify' do unless current_user.otp otp_error!(reason: '2FA has not been enabled for this account', error_code: 400, user: current_user.id, action: 'verify 2FA code', error_text: 'already_enabled') end unless TOTPService.validate?(current_user.uid, declared(params)[:code]) otp_error!(reason: 'OTP code is invalid', error_code: 422, user: current_user.id, action: 'verify 2FA code', error_text: 'invalid') end end end end end end