UNPKG

voluptasmollitia

Version:
206 lines (189 loc) 6.3 kB
/** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as exp from '@firebase/auth-exp/internal'; import * as compat from '@firebase/auth-types'; import { FirebaseError } from '@firebase/util'; import { Auth } from './auth'; import { User } from './user'; import { unwrap, wrapped } from './wrap'; function credentialFromResponse( userCredential: exp.UserCredentialInternal ): exp.AuthCredential | null { return credentialFromObject(userCredential); } function attachExtraErrorFields(auth: exp.Auth, e: FirebaseError): void { // The response contains all fields from the server which may or may not // actually match the underlying type const response = ((e.customData as exp.TaggedWithTokenResponse | undefined) ?._tokenResponse as unknown) as Record<string, string>; if (e.code === 'auth/multi-factor-auth-required') { const mfaErr = e as compat.MultiFactorError; mfaErr.resolver = new MultiFactorResolver( auth, exp.getMultiFactorResolver(auth, e as exp.MultiFactorError) ); } else if (response) { const credential = credentialFromObject(e); const credErr = e as compat.AuthError; if (credential) { credErr.credential = credential; credErr.tenantId = response.tenantId || undefined; credErr.email = response.email || undefined; credErr.phoneNumber = response.phoneNumber || undefined; } } } function credentialFromObject( object: FirebaseError | exp.UserCredential ): exp.AuthCredential | null { const { _tokenResponse } = (object instanceof FirebaseError ? object.customData : object) as exp.TaggedWithTokenResponse; if (!_tokenResponse) { return null; } // Handle phone Auth credential responses, as they have a different format // from other backend responses (i.e. no providerId). This is also only the // case for user credentials (does not work for errors). if (!(object instanceof FirebaseError)) { if ('temporaryProof' in _tokenResponse && 'phoneNumber' in _tokenResponse) { return exp.PhoneAuthProvider.credentialFromResult(object); } } const providerId = _tokenResponse.providerId; // Email and password is not supported as there is no situation where the // server would return the password to the client. if (!providerId || providerId === exp.ProviderId.PASSWORD) { return null; } let provider: Pick< typeof exp.OAuthProvider, 'credentialFromResult' | 'credentialFromError' >; switch (providerId) { case exp.ProviderId.GOOGLE: provider = exp.GoogleAuthProvider; break; case exp.ProviderId.FACEBOOK: provider = exp.FacebookAuthProvider; break; case exp.ProviderId.GITHUB: provider = exp.GithubAuthProvider; break; case exp.ProviderId.TWITTER: provider = exp.TwitterAuthProvider; break; default: const { oauthIdToken, oauthAccessToken, oauthTokenSecret, pendingToken, nonce } = _tokenResponse as exp.SignInWithIdpResponse; if ( !oauthAccessToken && !oauthTokenSecret && !oauthIdToken && !pendingToken ) { return null; } // TODO(avolkovi): uncomment this and get it working with SAML & OIDC if (pendingToken) { if (providerId.startsWith('saml.')) { return exp.SAMLAuthCredential._create(providerId, pendingToken); } else { // OIDC and non-default providers excluding Twitter. return exp.OAuthCredential._fromParams({ providerId, signInMethod: providerId, pendingToken, idToken: oauthIdToken, accessToken: oauthAccessToken }); } } return new exp.OAuthProvider(providerId).credential({ idToken: oauthIdToken, accessToken: oauthAccessToken, rawNonce: nonce }); } return object instanceof FirebaseError ? provider.credentialFromError(object) : provider.credentialFromResult(object); } export async function convertCredential( auth: exp.Auth, credentialPromise: Promise<exp.UserCredential> ): Promise<compat.UserCredential> { let credential: exp.UserCredential; try { credential = await credentialPromise; } catch (e) { if (e instanceof FirebaseError) { attachExtraErrorFields(auth, e); } throw e; } const { operationType, user } = credential; return { operationType, credential: credentialFromResponse( credential as exp.UserCredentialInternal ), additionalUserInfo: exp.getAdditionalUserInfo( credential as exp.UserCredential ), user: User.getOrCreate(user) }; } export async function convertConfirmationResult( auth: exp.Auth, confirmationResultPromise: Promise<exp.ConfirmationResult> ): Promise<compat.ConfirmationResult> { const confirmationResultExp = await confirmationResultPromise; return { verificationId: confirmationResultExp.verificationId, confirm: (verificationCode: string) => convertCredential(auth, confirmationResultExp.confirm(verificationCode)) }; } class MultiFactorResolver implements compat.MultiFactorResolver { readonly auth: Auth; constructor( auth: exp.Auth, private readonly resolver: exp.MultiFactorResolver ) { this.auth = wrapped(auth); } get session(): compat.MultiFactorSession { return this.resolver.session; } get hints(): compat.MultiFactorInfo[] { return this.resolver.hints; } resolveSignIn( assertion: compat.MultiFactorAssertion ): Promise<compat.UserCredential> { return convertCredential( unwrap(this.auth), this.resolver.resolveSignIn(assertion as exp.MultiFactorAssertion) ); } }