Skip to content

Commit 6f8136b

Browse files
authored
Merge 2f27f9d into 78df2a6
2 parents 78df2a6 + 2f27f9d commit 6f8136b

File tree

4 files changed

+162
-27
lines changed

4 files changed

+162
-27
lines changed

packages-exp/auth-exp/demo/src/index.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,18 +1220,18 @@ function onPopupRedirectProviderClick(_event) {
12201220
const providerId = $(event.currentTarget).data('provider');
12211221
let provider = null;
12221222
switch (providerId) {
1223-
case 'google.com':
1224-
provider = new GoogleAuthProvider();
1225-
break;
1226-
case 'facebook.com':
1227-
provider = new FacebookAuthProvider();
1228-
break;
1229-
case 'github.com':
1230-
provider = new GithubAuthProvider();
1231-
break;
1232-
case 'twitter.com':
1233-
provider = new TwitterAuthProvider();
1234-
break;
1223+
case 'google.com':
1224+
provider = new GoogleAuthProvider();
1225+
break;
1226+
case 'facebook.com':
1227+
provider = new FacebookAuthProvider();
1228+
break;
1229+
case 'github.com':
1230+
provider = new GithubAuthProvider();
1231+
break;
1232+
case 'twitter.com':
1233+
provider = new TwitterAuthProvider();
1234+
break;
12351235
default:
12361236
return;
12371237
}

packages-exp/auth-exp/src/api/index.test.ts

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { expect, use } from 'chai';
18+
import { assert, expect, use } from 'chai';
1919
import * as chaiAsPromised from 'chai-as-promised';
2020
import { SinonStub, stub, useFakeTimers } from 'sinon';
2121

@@ -180,10 +180,10 @@ describe('api/_performApiRequest', () => {
180180
{
181181
error: {
182182
code: 400,
183-
message: ServerError.EMAIL_EXISTS,
183+
message: ServerError.EXPIRED_OOB_CODE,
184184
errors: [
185185
{
186-
message: ServerError.EMAIL_EXISTS
186+
message: ServerError.EXPIRED_OOB_CODE
187187
}
188188
]
189189
}
@@ -196,7 +196,7 @@ describe('api/_performApiRequest', () => {
196196
Endpoint.SIGN_UP,
197197
request,
198198
{
199-
[ServerError.EMAIL_EXISTS]: AuthErrorCode.ARGUMENT_ERROR
199+
[ServerError.EXPIRED_OOB_CODE]: AuthErrorCode.ARGUMENT_ERROR
200200
}
201201
);
202202
await expect(promise).to.be.rejectedWith(
@@ -252,4 +252,88 @@ describe('api/_performApiRequest', () => {
252252
);
253253
});
254254
});
255+
256+
context('edgcase error mapping', () => {
257+
beforeEach(mockFetch.setUp);
258+
afterEach(mockFetch.tearDown);
259+
260+
it('should generate a need_conirmation error with the response', async () => {
261+
mockEndpoint(Endpoint.SIGN_UP, {
262+
needConfirmation: true,
263+
idToken: 'id-token'
264+
});
265+
try {
266+
await _performApiRequest<typeof request, typeof serverResponse>(
267+
auth,
268+
HttpMethod.POST,
269+
Endpoint.SIGN_UP,
270+
request
271+
);
272+
assert.fail('Call should have failed');
273+
} catch (e) {
274+
expect(e.code).to.eq(`auth/${AuthErrorCode.NEED_CONFIRMATION}`);
275+
expect(e._tokenResponse).to.eql({
276+
needConfirmation: true,
277+
idToken: 'id-token'
278+
});
279+
}
280+
});
281+
282+
it('should generate a credential already in use error', async () => {
283+
const response = {
284+
error: {
285+
code: 400,
286+
message: ServerError.FEDERATED_USER_ID_ALREADY_LINKED,
287+
errors: [
288+
{
289+
message: ServerError.FEDERATED_USER_ID_ALREADY_LINKED
290+
}
291+
]
292+
}
293+
};
294+
mockEndpoint(Endpoint.SIGN_UP, response, 400);
295+
try {
296+
await _performApiRequest<typeof request, typeof serverResponse>(
297+
auth,
298+
HttpMethod.POST,
299+
Endpoint.SIGN_UP,
300+
request
301+
);
302+
assert.fail('Call should have failed');
303+
} catch (e) {
304+
expect(e.code).to.eq(`auth/${AuthErrorCode.CREDENTIAL_ALREADY_IN_USE}`);
305+
expect(e._tokenResponse).to.eql(response);
306+
}
307+
});
308+
309+
it('should pull out email and phone number', async () => {
310+
const response = {
311+
error: {
312+
code: 400,
313+
message: ServerError.EMAIL_EXISTS,
314+
errors: [
315+
{
316+
message: ServerError.EMAIL_EXISTS
317+
}
318+
]
319+
},
320+
321+
phoneNumber: '+1555-this-is-a-number'
322+
};
323+
mockEndpoint(Endpoint.SIGN_UP, response, 400);
324+
try {
325+
await _performApiRequest<typeof request, typeof serverResponse>(
326+
auth,
327+
HttpMethod.POST,
328+
Endpoint.SIGN_UP,
329+
request
330+
);
331+
assert.fail('Call should have failed');
332+
} catch (e) {
333+
expect(e.code).to.eq(`auth/${AuthErrorCode.EMAIL_EXISTS}`);
334+
expect(e.email).to.eq('[email protected]');
335+
expect(e.phoneNumber).to.eq('+1555-this-is-a-number');
336+
}
337+
});
338+
});
255339
});

packages-exp/auth-exp/src/api/index.ts

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,17 @@
1717

1818
import { FirebaseError, querystring } from '@firebase/util';
1919

20-
import { AUTH_ERROR_FACTORY, AuthErrorCode } from '../core/errors';
21-
import { Delay } from '../core/util/delay';
22-
import { Auth } from '../model/auth';
23-
import { IdTokenResponse } from '../model/id_token';
2420
import {
25-
JsonError,
26-
SERVER_ERROR_MAP,
27-
ServerError,
28-
ServerErrorMap
29-
} from './errors';
21+
AUTH_ERROR_FACTORY,
22+
AuthErrorCode,
23+
NamedErrorParams
24+
} from '../core/errors';
3025
import { fail } from '../core/util/assert';
26+
import { Delay } from '../core/util/delay';
27+
import { Auth } from '../model/auth';
28+
import { IdTokenResponse, TaggedWithTokenResponse } from '../model/id_token';
3129
import { IdTokenMfaResponse } from './authentication/mfa';
30+
import { SERVER_ERROR_MAP, ServerError, ServerErrorMap } from './errors';
3231

3332
export enum HttpMethod {
3433
POST = 'POST',
@@ -121,11 +120,26 @@ export async function _performFetchWithErrorHandling<V>(
121120
fetchFn(),
122121
makeNetworkTimeout(auth.name)
123122
]);
123+
124+
const json = await response.json();
125+
if ('needConfirmation' in json) {
126+
throw makeTaggedError(auth, AuthErrorCode.NEED_CONFIRMATION, json);
127+
}
128+
124129
if (response.ok) {
125-
return response.json();
130+
return json;
126131
} else {
127-
const json: JsonError = await response.json();
128132
const serverErrorCode = json.error.message.split(' : ')[0] as ServerError;
133+
if (serverErrorCode === ServerError.FEDERATED_USER_ID_ALREADY_LINKED) {
134+
throw makeTaggedError(
135+
auth,
136+
AuthErrorCode.CREDENTIAL_ALREADY_IN_USE,
137+
json
138+
);
139+
} else if (serverErrorCode === ServerError.EMAIL_EXISTS) {
140+
throw makeTaggedError(auth, AuthErrorCode.EMAIL_EXISTS, json);
141+
}
142+
129143
const authError = errorMap[serverErrorCode];
130144
if (authError) {
131145
fail(auth.name, authError);
@@ -179,3 +193,29 @@ function makeNetworkTimeout<T>(appName: string): Promise<T> {
179193
}, DEFAULT_API_TIMEOUT_MS.get())
180194
);
181195
}
196+
197+
interface PotentialResponse extends IdTokenResponse {
198+
email?: string;
199+
phoneNumber?: string;
200+
}
201+
202+
function makeTaggedError(
203+
{ name }: Auth,
204+
code: AuthErrorCode,
205+
response: PotentialResponse
206+
): FirebaseError {
207+
const errorParams: NamedErrorParams = {
208+
appName: name
209+
};
210+
211+
if (response.email) {
212+
errorParams.email = response.email;
213+
}
214+
if (response.phoneNumber) {
215+
errorParams.phoneNumber = response.phoneNumber;
216+
}
217+
218+
const error = AUTH_ERROR_FACTORY.create(code, errorParams);
219+
(error as TaggedWithTokenResponse)._tokenResponse = response;
220+
return error;
221+
}

packages-exp/auth-exp/src/core/errors.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// eslint-disable-next-line import/no-extraneous-dependencies
1919
import * as externs from '@firebase/auth-types-exp';
2020
import { ErrorFactory, ErrorMap } from '@firebase/util';
21+
2122
import { AppName } from '../model/auth';
2223

2324
/*
@@ -329,6 +330,16 @@ const ERRORS: ErrorMap<AuthErrorCode> = {
329330
'This browser is not supported or 3rd party cookies and data may be disabled.'
330331
};
331332

333+
export interface NamedErrorParams {
334+
appName: AppName;
335+
credential?: externs.AuthCredential;
336+
email?: string;
337+
phoneNumber?: string;
338+
tenantId?: string;
339+
user?: externs.User;
340+
serverResponse?: object;
341+
}
342+
332343
type AuthErrorParams = {
333344
[key in AuthErrorCode]: {
334345
appName: AppName;

0 commit comments

Comments
 (0)