Class: FirebaseApiService
- Inherits:
-
Object
- Object
- FirebaseApiService
- Defined in:
- app/services/firebase_api_service.rb
Constant Summary collapse
- FIREBASE_PROJECT_ID =
Rails.application.credentials.firebase_project_id
Class Method Summary collapse
- .access_token ⇒ Object
- .conn ⇒ Object
- .create_firebase_user(email) ⇒ Object
- .create_password_and_verify_email(oob_code, new_password) ⇒ Object
- .create_password_and_verify_email_link(user:, app_mode:) ⇒ Object
- .email_link(purpose:, user_id:, app_mode:, locale: 'en') ⇒ Object
- .email_verification_link(user:, app_mode:) ⇒ Object
- .find_firebase_user(email) ⇒ Object
- .find_or_register_user(credential, app_mode) ⇒ Object
- .firebase_user(email) ⇒ Object
- .firebase_user_verified?(email) ⇒ Boolean
- .password_reset_link(user:, app_mode:) ⇒ Object
- .reset_password(oob_code, new_password) ⇒ Object
- .reset_password_on_firebase!(email, password) ⇒ Object
- .send_password_reset_email(email, app_mode) ⇒ Object
- .send_verification_email(credential, app_mode) ⇒ Object
- .verify_email(oob_code) ⇒ Object
- .verify_email_on_firebase!(email) ⇒ Object
- .verify_id_token(id_token:) ⇒ Object
- .verify_oob_code!(oob_code, purpose) ⇒ Object
Class Method Details
.access_token ⇒ Object
219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'app/services/firebase_api_service.rb', line 219 def access_token @access_token ||= begin scopes = [ 'https://www.googleapis.com/auth/identitytoolkit' ] = Google::Auth::ServiceAccountCredentials.make_creds( json_key_io: StringIO.new(Rails.application.credentials.firebase_service_account), scope: scopes ) .fetch_access_token!['access_token'] end end |
.conn ⇒ Object
232 233 234 235 236 237 238 239 240 |
# File 'app/services/firebase_api_service.rb', line 232 def conn @conn ||= Faraday.new(url: 'https://identitytoolkit.googleapis.com') do |faraday| faraday.request :json faraday.response :json faraday.response :raise_error faraday.headers['Authorization'] = "Bearer #{access_token}" faraday.adapter Faraday.default_adapter end end |
.create_firebase_user(email) ⇒ Object
169 170 171 172 |
# File 'app/services/firebase_api_service.rb', line 169 def create_firebase_user(email) response = conn.post('/v1/accounts:signUp', { email: email }) response.body end |
.create_password_and_verify_email(oob_code, new_password) ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'app/services/firebase_api_service.rb', line 109 def create_password_and_verify_email(oob_code, new_password) purpose = Auth::Token::PURPOSES[:create_password_and_verify_email] user = verify_oob_code!(oob_code, purpose) email = user.email reset_password_on_firebase!(email, new_password) verify_email_on_firebase!(email) RevokedToken.create!(token: oob_code, erp_user_id: user.id, reason: RevokedToken::REASONS[:USED]) user end |
.create_password_and_verify_email_link(user:, app_mode:) ⇒ Object
192 193 194 195 196 197 198 199 |
# File 'app/services/firebase_api_service.rb', line 192 def create_password_and_verify_email_link(user:, app_mode:) email_link( purpose: Auth::Token::PURPOSES[:create_password_and_verify_email], user_id: user.id, locale: user.locale, app_mode: app_mode ) end |
.email_link(purpose:, user_id:, app_mode:, locale: 'en') ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'app/services/firebase_api_service.rb', line 201 def email_link(purpose:, user_id:, app_mode:, locale: 'en') oob_code = Auth::Token.encode( user_id: user_id, purposes: [purpose] ) base_url = "#{app_mode.web_uri}/auth/email_action" query_params = { purpose: purpose, oobCode: oob_code, locale: locale } uri = URI(base_url) uri.query = URI.encode_www_form(query_params) uri.to_s end |
.email_verification_link(user:, app_mode:) ⇒ Object
174 175 176 177 178 179 180 181 |
# File 'app/services/firebase_api_service.rb', line 174 def email_verification_link(user:, app_mode:) email_link( purpose: Auth::Token::PURPOSES[:verify_email], user_id: user.id, locale: user.locale, app_mode: app_mode ) end |
.find_firebase_user(email) ⇒ Object
159 160 161 162 163 164 165 166 167 |
# File 'app/services/firebase_api_service.rb', line 159 def find_firebase_user(email) response = conn.post('/v1/accounts:lookup', { email: email }) firebase_user_data = response.body.dig('users', 0) raise ActiveRecord::RecordNotFound unless firebase_user_data firebase_user_data rescue ActiveRecord::RecordNotFound nil end |
.find_or_register_user(credential, app_mode) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 |
# File 'app/services/firebase_api_service.rb', line 33 def find_or_register_user(credential, app_mode) id_token = credential['_tokenResponse']['idToken'] user_data = verify_id_token(id_token: id_token) email = user_data[:email] ErpUser.find_by(email: email) || UserRegistrationService.new( email: email, navigation_configuration_id: app_mode., permission_groups_codes: app_mode. ).register end |
.firebase_user(email) ⇒ Object
155 156 157 |
# File 'app/services/firebase_api_service.rb', line 155 def firebase_user(email) find_firebase_user(email) || create_firebase_user(email) end |
.firebase_user_verified?(email) ⇒ Boolean
123 124 125 |
# File 'app/services/firebase_api_service.rb', line 123 def firebase_user_verified?(email) firebase_user(email)['emailVerified'] end |
.password_reset_link(user:, app_mode:) ⇒ Object
183 184 185 186 187 188 189 190 |
# File 'app/services/firebase_api_service.rb', line 183 def password_reset_link(user:, app_mode:) email_link( purpose: Auth::Token::PURPOSES[:reset_password], user_id: user.id, locale: user.locale, app_mode: app_mode ) end |
.reset_password(oob_code, new_password) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'app/services/firebase_api_service.rb', line 96 def reset_password(oob_code, new_password) purpose = Auth::Token::PURPOSES[:reset_password] user = verify_oob_code!(oob_code, purpose) email = user.email reset_password_on_firebase!(email, new_password) RevokedToken.create!(token: oob_code, erp_user_id: user.id, reason: RevokedToken::REASONS[:USED]) user end |
.reset_password_on_firebase!(email, password) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'app/services/firebase_api_service.rb', line 139 def reset_password_on_firebase!(email, password) response = firebase_user(email) remote_id = response['localId'] update_response = conn.post( '/v1/accounts:update', { localId: remote_id, password: password, emailVerified: true } ) update_response.body end |
.send_password_reset_email(email, app_mode) ⇒ Object
56 57 58 59 60 61 62 63 64 65 |
# File 'app/services/firebase_api_service.rb', line 56 def send_password_reset_email(email, app_mode) user = ErpUser.find_by!(email: email) link = password_reset_link(user: user, app_mode: app_mode) AuthMailer.password_reset( user: user, link: link, app_mode: app_mode ).deliver_now end |
.send_verification_email(credential, app_mode) ⇒ Object
45 46 47 48 49 50 51 52 53 54 |
# File 'app/services/firebase_api_service.rb', line 45 def send_verification_email(credential, app_mode) user = find_or_register_user(credential, app_mode) link = email_verification_link(user: user, app_mode: app_mode) AuthMailer.verification( user: user, link: link, app_mode: app_mode ).deliver_now end |
.verify_email(oob_code) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 |
# File 'app/services/firebase_api_service.rb', line 84 def verify_email(oob_code) purpose = Auth::Token::PURPOSES[:verify_email] user = verify_oob_code!(oob_code, purpose) email = user.email verify_email_on_firebase!(email) RevokedToken.create!(token: oob_code, erp_user_id: user.id, reason: RevokedToken::REASONS[:USED]) user end |
.verify_email_on_firebase!(email) ⇒ Object
127 128 129 130 131 132 133 134 135 136 137 |
# File 'app/services/firebase_api_service.rb', line 127 def verify_email_on_firebase!(email) remote_id = firebase_user(email)['localId'] response = conn.post( '/v1/accounts:update', { localId: remote_id, emailVerified: true } ) response.body['emailVerified'] end |
.verify_id_token(id_token:) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'app/services/firebase_api_service.rb', line 5 def verify_id_token(id_token:) header = JWT.decode(id_token, nil, false)[1] kid = header['kid'] uri = URI('https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com') public_keys = JSON.parse(Net::HTTP.get(uri)) public_key = public_keys[kid] x509 = OpenSSL::X509::Certificate.new public_key result = JWT.decode( id_token.strip, x509.public_key, true, { algorithm: 'RS256', verify_iat: true, iss: "https://securetoken.google.com/#{FIREBASE_PROJECT_ID}", aud: FIREBASE_PROJECT_ID } ) email = result.dig(0, 'firebase', 'identities', 'email', 0) { email: email } end |
.verify_oob_code!(oob_code, purpose) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'app/services/firebase_api_service.rb', line 67 def verify_oob_code!(oob_code, purpose) decoded = Auth::Token.decode(token: oob_code, purposes: [purpose]) user_id = decoded[:user_id] user = ErpUser.find(user_id) if RevokedToken.exists?(token: oob_code, erp_user_id: user_id, reason: RevokedToken::REASONS[:USED]) raise 'OOB code already used' end if purpose == Auth::Token::PURPOSES[:verify_email] && firebase_user_verified?(user.email) raise 'User already verified' end user end |