[auth][wip] improve error codes, messages and types

This commit is contained in:
Salakar 2018-08-22 17:55:53 +01:00
parent 434d43d713
commit 2092a32f46
16 changed files with 318 additions and 124 deletions

View File

@ -1,21 +1,78 @@
#ifndef RNFirebaseAuth_h #ifndef RNFirebaseAuth_h
#define RNFirebaseAuth_h #define RNFirebaseAuth_h
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#if __has_include(<FirebaseAuth/FIRAuth.h>)
#import <Firebase.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#if __has_include(<FirebaseAuth/FIRAuth.h>) @interface RNFirebaseAuth : RCTEventEmitter <RCTBridgeModule> {};
#import <Firebase.h> @property NSMutableDictionary *authStateHandlers;
#import <React/RCTBridgeModule.h> @property NSMutableDictionary *idTokenHandlers;
#import <React/RCTEventEmitter.h> @end
@interface RNFirebaseAuth : RCTEventEmitter <RCTBridgeModule> {};
@property NSMutableDictionary *authStateHandlers;
@property NSMutableDictionary *idTokenHandlers;
@end
#else
@interface RNFirebaseAuth : NSObject
@end
#endif
extern NSString * const AuthErrorCode_toJSErrorCode[];
NSString * const AuthErrorCode_toJSErrorCode[] = {
[FIRAuthErrorCodeInvalidCustomToken] = @"invalid-custom-token",
[FIRAuthErrorCodeCustomTokenMismatch] = @"custom-token-mismatch",
[FIRAuthErrorCodeInvalidCredential] = @"invalid-credential",
[FIRAuthErrorCodeUserDisabled] = @"user-disabled",
[FIRAuthErrorCodeOperationNotAllowed] = @"operation-not-allowed",
[FIRAuthErrorCodeEmailAlreadyInUse] = @"email-already-in-use",
[FIRAuthErrorCodeInvalidEmail] = @"invalid-email",
[FIRAuthErrorCodeWrongPassword] = @"wrong-password",
[FIRAuthErrorCodeTooManyRequests] = @"too-many-requests",
[FIRAuthErrorCodeUserNotFound] = @"user-not-found",
[FIRAuthErrorCodeAccountExistsWithDifferentCredential] = @"account-exists-with-different-credential",
[FIRAuthErrorCodeRequiresRecentLogin] = @"requires-recent-login",
[FIRAuthErrorCodeProviderAlreadyLinked] = @"provider-already-linked",
[FIRAuthErrorCodeNoSuchProvider] = @"no-such-provider",
[FIRAuthErrorCodeInvalidUserToken] = @"invalid-user-token",
[FIRAuthErrorCodeNetworkError] = @"network-request-failed",
[FIRAuthErrorCodeUserTokenExpired] = @"user-token-expired",
[FIRAuthErrorCodeInvalidAPIKey] = @"invalid-api-key",
[FIRAuthErrorCodeUserMismatch] = @"user-mismatch",
[FIRAuthErrorCodeCredentialAlreadyInUse] = @"credential-already-in-use",
[FIRAuthErrorCodeWeakPassword] = @"weak-password",
[FIRAuthErrorCodeAppNotAuthorized] = @"app-not-authorized",
[FIRAuthErrorCodeExpiredActionCode] = @"expired-action-code",
[FIRAuthErrorCodeInvalidActionCode] = @"invalid-action-code",
[FIRAuthErrorCodeInvalidMessagePayload] = @"invalid-message-payload",
[FIRAuthErrorCodeInvalidSender] = @"invalid-sender",
[FIRAuthErrorCodeInvalidRecipientEmail] = @"invalid-recipient-email",
[FIRAuthErrorCodeMissingEmail] = @"invalid-email",
[FIRAuthErrorCodeMissingIosBundleID] = @"missing-ios-bundle-id",
[FIRAuthErrorCodeMissingAndroidPackageName] = @"missing-android-pkg-name",
[FIRAuthErrorCodeUnauthorizedDomain] = @"unauthorized-domain",
[FIRAuthErrorCodeInvalidContinueURI] = @"invalid-continue-uri",
[FIRAuthErrorCodeMissingContinueURI] = @"missing-continue-uri",
[FIRAuthErrorCodeMissingPhoneNumber] = @"missing-phone-number",
[FIRAuthErrorCodeInvalidPhoneNumber] = @"invalid-phone-number",
[FIRAuthErrorCodeMissingVerificationCode] = @"missing-verification-code",
[FIRAuthErrorCodeInvalidVerificationCode] = @"invalid-verification-code",
[FIRAuthErrorCodeMissingVerificationID] = @"missing-verification-id",
[FIRAuthErrorCodeInvalidVerificationID] = @"invalid-verification-id",
[FIRAuthErrorCodeMissingAppCredential] = @"missing-app-credential",
[FIRAuthErrorCodeInvalidAppCredential] = @"invalid-app-credential",
[FIRAuthErrorCodeSessionExpired] = @"code-expired",
[FIRAuthErrorCodeQuotaExceeded] = @"quota-exceeded",
[FIRAuthErrorCodeMissingAppToken] = @"missing-apns-token",
[FIRAuthErrorCodeNotificationNotForwarded] = @"notification-not-forwarded",
[FIRAuthErrorCodeAppNotVerified] = @"app-not-verified",
[FIRAuthErrorCodeCaptchaCheckFailed] = @"captcha-check-failed",
[FIRAuthErrorCodeWebContextAlreadyPresented] = @"cancelled-popup-request",
[FIRAuthErrorCodeWebContextCancelled] = @"popup-closed-by-user",
[FIRAuthErrorCodeAppVerificationUserInteractionFailure] = @"app-verification-user-interaction-failure",
[FIRAuthErrorCodeInvalidClientID] = @"invalid-oauth-client-id",
[FIRAuthErrorCodeWebNetworkRequestFailed] = @"network-request-failed",
[FIRAuthErrorCodeWebInternalError] = @"internal-error",
[FIRAuthErrorCodeNullUser] = @"null-user",
[FIRAuthErrorCodeKeychainError] = @"keychain-error",
[FIRAuthErrorCodeInternalError] = @"internal-error",
[FIRAuthErrorCodeMalformedJWT] = @"malformed-jwt"
};
#else
@interface RNFirebaseAuth : NSObject
@end
#endif
#endif #endif

View File

@ -1224,7 +1224,9 @@ RCT_EXPORT_METHOD(verifyPasswordResetCode:(NSString *) appDisplayName
NSString *code = @"auth/unknown"; NSString *code = @"auth/unknown";
NSString *message = [error localizedDescription]; NSString *message = [error localizedDescription];
NSString *nativeErrorMessage = [error localizedDescription]; NSString *nativeErrorMessage = [error localizedDescription];
code = AuthErrorCode_toJSErrorCode[error.code];
// TODO remove switch case after testing AuthErrorCode_toJSErrorCode
switch (error.code) { switch (error.code) {
case FIRAuthErrorCodeInvalidCustomToken: case FIRAuthErrorCodeInvalidCustomToken:
code = @"auth/invalid-custom-token"; code = @"auth/invalid-custom-token";
@ -1298,8 +1300,6 @@ RCT_EXPORT_METHOD(verifyPasswordResetCode:(NSString *) appDisplayName
code = @"auth/internal-error"; code = @"auth/internal-error";
message = @"An internal error has occurred, please try again."; message = @"An internal error has occurred, please try again.";
break; break;
// unsure of the below codes so leaving them as the default error message
case FIRAuthErrorCodeTooManyRequests: case FIRAuthErrorCodeTooManyRequests:
code = @"auth/too-many-requests"; code = @"auth/too-many-requests";
break; break;
@ -1330,6 +1330,18 @@ RCT_EXPORT_METHOD(verifyPasswordResetCode:(NSString *) appDisplayName
case FIRAuthErrorCodeKeychainError: case FIRAuthErrorCodeKeychainError:
code = @"auth/keychain-error"; code = @"auth/keychain-error";
break; break;
case FIRAuthErrorCodeInvalidVerificationCode:
code = @"auth/invalid-verification-code";
message = @"The verification code used to create the phone auth credential is invalid";
break;
case FIRAuthErrorCodeInvalidVerificationID:
code = @"auth/invalid-verification-id";
message = @"The verification ID used to create the phone auth credential is invalid";
break;
case FIRAuthErrorCodeInvalidActionCode:
code = @"auth/invalid-action-code";
message = @"The action code is invalid. This can happen if the code is malformed, expired, or has already been used.";
break;
default: default:
break; break;
} }

View File

@ -0,0 +1,33 @@
import type { AuthErrorCode } from './types.flow';
export default class AuthError {
+code: AuthErrorCode;
+message: string;
+nativeMessage: string;
+credential: ?any;
/**
*
* @param code
* @param nativeMessage
* @param credential
*/
constructor(
code: AuthErrorCode,
nativeMessage: string,
credential?: any // TODO AuthCredential type
) {
// this.code = code;
// this.details = details;
// this.message = message;
// TODO babel 7 issue... can't extend builtin classes properly.
this._error = new Error(''); // TODO code to message lookup or revert to nativeMessage
this._error.code = code;
this._error.credential = credential;
this._error.constructor = AuthError;
return this._error;
}
}

View File

@ -5,7 +5,6 @@
import INTERNALS from '../../utils/internals'; import INTERNALS from '../../utils/internals';
import { getNativeModule } from '../../utils/native'; import { getNativeModule } from '../../utils/native';
import type Auth from '.';
import type { import type {
ActionCodeSettings, ActionCodeSettings,
AuthCredential, AuthCredential,
@ -13,7 +12,9 @@ import type {
UserCredential, UserCredential,
UserInfo, UserInfo,
UserMetadata, UserMetadata,
} from './types'; } from './types.flow';
import type Auth from '.';
type UpdateProfile = { type UpdateProfile = {
displayName?: string, displayName?: string,

View File

@ -3,32 +3,33 @@
* Auth representation wrapper * Auth representation wrapper
*/ */
import User from './User'; import User from './User';
import ModuleBase from '../../utils/ModuleBase';
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import { isAndroid, isBoolean } from '../../utils';
import { getLogger } from '../../utils/log'; import { getLogger } from '../../utils/log';
import { getNativeModule } from '../../utils/native';
import INTERNALS from '../../utils/internals'; import INTERNALS from '../../utils/internals';
import ConfirmationResult from './phone/ConfirmationResult'; import ModuleBase from '../../utils/ModuleBase';
import { isAndroid, isBoolean } from '../../utils';
import { getNativeModule } from '../../utils/native';
import PhoneAuthListener from './phone/PhoneAuthListener'; import PhoneAuthListener from './phone/PhoneAuthListener';
import ConfirmationResult from './phone/ConfirmationResult';
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
// providers // providers
import OAuthProvider from './providers/OAuthProvider';
import EmailAuthProvider from './providers/EmailAuthProvider'; import EmailAuthProvider from './providers/EmailAuthProvider';
import PhoneAuthProvider from './providers/PhoneAuthProvider'; import PhoneAuthProvider from './providers/PhoneAuthProvider';
import GoogleAuthProvider from './providers/GoogleAuthProvider'; import GoogleAuthProvider from './providers/GoogleAuthProvider';
import GithubAuthProvider from './providers/GithubAuthProvider'; import GithubAuthProvider from './providers/GithubAuthProvider';
import OAuthProvider from './providers/OAuthProvider';
import TwitterAuthProvider from './providers/TwitterAuthProvider'; import TwitterAuthProvider from './providers/TwitterAuthProvider';
import FacebookAuthProvider from './providers/FacebookAuthProvider'; import FacebookAuthProvider from './providers/FacebookAuthProvider';
import type { import type {
ActionCodeInfo,
ActionCodeSettings,
AuthCredential,
NativeUser, NativeUser,
NativeUserCredential, AuthCredential,
ActionCodeInfo,
UserCredential, UserCredential,
} from './types'; ActionCodeSettings,
NativeUserCredential,
} from './types.flow';
import type App from '../core/app'; import type App from '../core/app';
type AuthState = { type AuthState = {
@ -526,7 +527,7 @@ export default class Auth extends ModuleBase {
* @param code * @param code
* @returns {*} * @returns {*}
*/ */
set languageCode(code: string) { set languageCode(code: string): void {
this._languageCode = code; this._languageCode = code;
getNativeModule(this).setLanguageCode(code); getNativeModule(this).setLanguageCode(code);
} }

View File

@ -3,6 +3,7 @@
* ConfirmationResult representation wrapper * ConfirmationResult representation wrapper
*/ */
import { getNativeModule } from '../../../utils/native'; import { getNativeModule } from '../../../utils/native';
import type Auth from '..'; import type Auth from '..';
import type User from '../User'; import type User from '../User';

View File

@ -1,23 +1,23 @@
// @flow // @flow
import INTERNALS from '../../../utils/internals';
import { SharedEventEmitter } from '../../../utils/events';
import { import {
generatePushID,
isFunction,
isAndroid,
isIOS, isIOS,
isString, isString,
isAndroid,
isFunction,
generatePushID,
nativeToJSError, nativeToJSError,
} from '../../../utils'; } from '../../../utils';
import INTERNALS from '../../../utils/internals';
import { getNativeModule } from '../../../utils/native'; import { getNativeModule } from '../../../utils/native';
import { SharedEventEmitter } from '../../../utils/events';
import type Auth from '..'; import type Auth from '..';
type PhoneAuthSnapshot = { type PhoneAuthSnapshot = {
state: 'sent' | 'timeout' | 'verified' | 'error',
verificationId: string,
code: string | null,
error: Error | null, error: Error | null,
code: string | null,
verificationId: string,
state: 'sent' | 'timeout' | 'verified' | 'error',
}; };
type PhoneAuthError = { type PhoneAuthError = {
@ -194,6 +194,7 @@ export default class PhoneAuthListener {
/** /**
* Create a new internal deferred promise, if not already created * Create a new internal deferred promise, if not already created
* @private * @private
* TODO use promise deferred util
*/ */
_promiseDeferred() { _promiseDeferred() {
if (!this._promise) { if (!this._promise) {
@ -341,6 +342,7 @@ export default class PhoneAuthListener {
return this; return this;
} }
// TODO have these inherit from extending a ThenableClass util/helper?
/** /**
* Promise .then proxy * Promise .then proxy
* @param fn * @param fn

View File

@ -2,7 +2,7 @@
* @flow * @flow
* EmailAuthProvider representation wrapper * EmailAuthProvider representation wrapper
*/ */
import type { AuthCredential } from '../types'; import type { AuthCredential } from '../types.flow';
const linkProviderId = 'emailLink'; const linkProviderId = 'emailLink';
const passwordProviderId = 'password'; const passwordProviderId = 'password';

View File

@ -2,7 +2,7 @@
* @flow * @flow
* FacebookAuthProvider representation wrapper * FacebookAuthProvider representation wrapper
*/ */
import type { AuthCredential } from '../types'; import type { AuthCredential } from '../types.flow';
const providerId = 'facebook.com'; const providerId = 'facebook.com';

View File

@ -2,7 +2,7 @@
* @flow * @flow
* GithubAuthProvider representation wrapper * GithubAuthProvider representation wrapper
*/ */
import type { AuthCredential } from '../types'; import type { AuthCredential } from '../types.flow';
const providerId = 'github.com'; const providerId = 'github.com';

View File

@ -2,7 +2,7 @@
* @flow * @flow
* EmailAuthProvider representation wrapper * EmailAuthProvider representation wrapper
*/ */
import type { AuthCredential } from '../types'; import type { AuthCredential } from '../types.flow';
const providerId = 'google.com'; const providerId = 'google.com';

View File

@ -2,7 +2,7 @@
* @flow * @flow
* OAuthProvider representation wrapper * OAuthProvider representation wrapper
*/ */
import type { AuthCredential } from '../types'; import type { AuthCredential } from '../types.flow';
const providerId = 'oauth'; const providerId = 'oauth';

View File

@ -2,7 +2,7 @@
* @flow * @flow
* PhoneAuthProvider representation wrapper * PhoneAuthProvider representation wrapper
*/ */
import type { AuthCredential } from '../types'; import type { AuthCredential } from '../types.flow';
const providerId = 'phone'; const providerId = 'phone';

View File

@ -2,7 +2,7 @@
* @flow * @flow
* TwitterAuthProvider representation wrapper * TwitterAuthProvider representation wrapper
*/ */
import type { AuthCredential } from '../types'; import type { AuthCredential } from '../types.flow';
const providerId = 'twitter.com'; const providerId = 'twitter.com';

View File

@ -0,0 +1,162 @@
/**
* @flow
*/
import type User from './User';
export type ActionCodeInfo = {
data: {
email?: string,
fromEmail?: string,
},
operation: 'PASSWORD_RESET' | 'VERIFY_EMAIL' | 'RECOVER_EMAIL',
};
export type ActionCodeSettings = {
android: {
installApp?: boolean,
minimumVersion?: string,
packageName: string,
},
handleCodeInApp?: boolean,
iOS: {
bundleId?: string,
},
url: string,
};
export type AdditionalUserInfo = {
isNewUser: boolean,
profile?: Object,
providerId: string,
username?: string,
};
export type AuthCredential = {
providerId: string,
token: string,
secret: string,
};
export type UserCredential = {|
additionalUserInfo?: AdditionalUserInfo,
user: User,
|};
export type UserInfo = {
displayName?: string,
email?: string,
phoneNumber?: string,
photoURL?: string,
providerId: string,
uid: string,
};
export type UserMetadata = {
creationTime?: string,
lastSignInTime?: string,
};
export type NativeUser = {
displayName?: string,
email?: string,
emailVerified?: boolean,
isAnonymous?: boolean,
metadata: UserMetadata,
phoneNumber?: string,
photoURL?: string,
providerData: UserInfo[],
providerId: string,
uid: string,
};
export type NativeUserCredential = {|
additionalUserInfo?: AdditionalUserInfo,
user: NativeUser,
|};
export type AuthErrorCode =
| 'account-exists-with-different-credential'
| 'app-deleted'
| 'app-not-authorized'
| 'app-not-installed'
| 'app-not-verified'
| 'app-verification-user-interaction-failure'
| 'argument-error'
| 'auth-domain-config-required'
| 'cancelled-popup-request'
| 'cancelled-popup-request'
| 'captcha-check-failed'
| 'code-expired'
| 'code-expired'
| 'credential-already-in-use'
| 'custom-token-mismatch'
| 'dynamic-link-not-activated'
| 'email-already-in-use'
| 'expired-action-code'
| 'internal-error'
| 'internal-error'
| 'invalid-action-code'
| 'invalid-api-key'
| 'invalid-app-credential'
| 'invalid-app-id'
| 'invalid-auth-event'
| 'invalid-cert-hash'
| 'invalid-continue-uri'
| 'invalid-credential'
| 'invalid-custom-token'
| 'invalid-email'
| 'invalid-email'
| 'invalid-message-payload'
| 'invalid-oauth-client-id'
| 'invalid-oauth-client-id'
| 'invalid-oauth-provider'
| 'invalid-persistence-type'
| 'invalid-phone-number'
| 'invalid-provider-id'
| 'invalid-recipient-email'
| 'invalid-sender'
| 'invalid-user-token'
| 'invalid-verification-code'
| 'invalid-verification-id'
| 'keychain-error'
| 'malformed-jwt'
| 'missing-android-pkg-name'
| 'missing-android-pkg-name'
| 'missing-apns-token'
| 'missing-app-credential'
| 'missing-continue-uri'
| 'missing-ios-bundle-id'
| 'missing-phone-number'
| 'missing-verification-code'
| 'missing-verification-id'
| 'network-request-failed'
| 'network-request-failed'
| 'network-request-failed'
| 'no-auth-event'
| 'no-such-provider'
| 'notification-not-forwarded'
| 'null-user'
| 'operation-not-allowed'
| 'operation-not-supported-in-this-environment'
| 'popup-blocked'
| 'popup-closed-by-user'
| 'popup-closed-by-user'
| 'provider-already-linked'
| 'quota-exceeded'
| 'redirect-cancelled-by-user'
| 'redirect-operation-pending'
| 'requires-recent-login'
| 'timeout'
| 'too-many-requests'
| 'unauthorized-continue-uri'
| 'unauthorized-domain'
| 'unsupported-persistence-type'
| 'user-cancelled'
| 'user-disabled'
| 'user-mismatch'
| 'user-not-found'
| 'user-signed-out'
| 'user-token-expired'
| 'weak-password'
| 'web-storage-unsupported'
| 'wrong-password';

View File

@ -1,75 +0,0 @@
/**
* @flow
*/
import type User from './User';
export type ActionCodeInfo = {
data: {
email?: string,
fromEmail?: string,
},
operation: 'PASSWORD_RESET' | 'VERIFY_EMAIL' | 'RECOVER_EMAIL',
};
export type ActionCodeSettings = {
android: {
installApp?: boolean,
minimumVersion?: string,
packageName: string,
},
handleCodeInApp?: boolean,
iOS: {
bundleId?: string,
},
url: string,
};
export type AdditionalUserInfo = {
isNewUser: boolean,
profile?: Object,
providerId: string,
username?: string,
};
export type AuthCredential = {
providerId: string,
token: string,
secret: string,
};
export type UserCredential = {|
additionalUserInfo?: AdditionalUserInfo,
user: User,
|};
export type UserInfo = {
displayName?: string,
email?: string,
phoneNumber?: string,
photoURL?: string,
providerId: string,
uid: string,
};
export type UserMetadata = {
creationTime?: string,
lastSignInTime?: string,
};
export type NativeUser = {
displayName?: string,
email?: string,
emailVerified?: boolean,
isAnonymous?: boolean,
metadata: UserMetadata,
phoneNumber?: string,
photoURL?: string,
providerData: UserInfo[],
providerId: string,
uid: string,
};
export type NativeUserCredential = {|
additionalUserInfo?: AdditionalUserInfo,
user: NativeUser,
|};