voluptasmollitia
Version:
Monorepo for the Firebase JavaScript SDK
140 lines (128 loc) • 4.66 kB
text/typescript
/**
* @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 {
Auth,
MultiFactorResolver,
OperationType,
UserCredential,
MultiFactorError
} from '../model/public_types';
import { _castAuth } from '../core/auth/auth_impl';
import { AuthErrorCode } from '../core/errors';
import { UserCredentialImpl } from '../core/user/user_credential_impl';
import { _assert, _fail } from '../core/util/assert';
import { UserCredentialInternal } from '../model/user';
import { MultiFactorAssertionImpl } from './mfa_assertion';
import { MultiFactorError as MultiFactorErrorInternal } from './mfa_error';
import { MultiFactorInfoImpl } from './mfa_info';
import { MultiFactorSessionImpl } from './mfa_session';
import { getModularInstance } from '@firebase/util';
export class MultiFactorResolverImpl implements MultiFactorResolver {
private constructor(
readonly session: MultiFactorSessionImpl,
readonly hints: MultiFactorInfoImpl[],
private readonly signInResolver: (
assertion: MultiFactorAssertionImpl
) => Promise<UserCredentialInternal>
) {}
/** @internal */
static _fromError(
authExtern: Auth,
error: MultiFactorErrorInternal
): MultiFactorResolverImpl {
const auth = _castAuth(authExtern);
const hints = (error.serverResponse.mfaInfo || []).map(enrollment =>
MultiFactorInfoImpl._fromServerResponse(auth, enrollment)
);
_assert(
error.serverResponse.mfaPendingCredential,
auth,
AuthErrorCode.INTERNAL_ERROR
);
const session = MultiFactorSessionImpl._fromMfaPendingCredential(
error.serverResponse.mfaPendingCredential
);
return new MultiFactorResolverImpl(
session,
hints,
async (
assertion: MultiFactorAssertionImpl
): Promise<UserCredentialInternal> => {
const mfaResponse = await assertion._process(auth, session);
// Clear out the unneeded fields from the old login response
delete error.serverResponse.mfaInfo;
delete error.serverResponse.mfaPendingCredential;
// Use in the new token & refresh token in the old response
const idTokenResponse = {
...error.serverResponse,
idToken: mfaResponse.idToken,
refreshToken: mfaResponse.refreshToken
};
// TODO: we should collapse this switch statement into UserCredentialImpl._forOperation and have it support the SIGN_IN case
switch (error.operationType) {
case OperationType.SIGN_IN:
const userCredential = await UserCredentialImpl._fromIdTokenResponse(
auth,
error.operationType,
idTokenResponse
);
await auth._updateCurrentUser(userCredential.user);
return userCredential;
case OperationType.REAUTHENTICATE:
_assert(error.user, auth, AuthErrorCode.INTERNAL_ERROR);
return UserCredentialImpl._forOperation(
error.user,
error.operationType,
idTokenResponse
);
default:
_fail(auth, AuthErrorCode.INTERNAL_ERROR);
}
}
);
}
async resolveSignIn(
assertionExtern: MultiFactorAssertionImpl
): Promise<UserCredential> {
const assertion = assertionExtern as MultiFactorAssertionImpl;
return this.signInResolver(assertion);
}
}
/**
* Provides a {@link MultiFactorResolver} suitable for completion of a
* multi-factor flow.
*
* @param auth - The auth instance.
* @param error - The {@link MultiFactorError} raised during a sign-in, or
* reauthentication operation.
*
* @public
*/
export function getMultiFactorResolver(
auth: Auth,
error: MultiFactorError
): MultiFactorResolver {
const authModular = getModularInstance(auth);
const errorInternal = error as MultiFactorErrorInternal;
_assert(error.operationType, authModular, AuthErrorCode.ARGUMENT_ERROR);
_assert(
errorInternal.serverResponse?.mfaPendingCredential,
authModular,
AuthErrorCode.ARGUMENT_ERROR
);
return MultiFactorResolverImpl._fromError(authModular, errorInternal);
}