@umituz/react-native-firebase 2.6.3 → 2.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/application/auth/index.ts +2 -34
- package/src/application/auth/use-cases/index.ts +1 -21
- package/src/domains/account-deletion/domain/index.ts +1 -8
- package/src/domains/account-deletion/index.ts +0 -42
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor.ts +79 -0
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionTypes.ts +0 -1
- package/src/domains/account-deletion/infrastructure/services/account-deletion.service.ts +2 -14
- package/src/domains/auth/index.ts +3 -12
- package/src/domains/auth/infrastructure/config/FirebaseAuthClient.ts +48 -60
- package/src/domains/auth/infrastructure/config/index.ts +2 -0
- package/src/domains/auth/infrastructure/config/initializers/index.ts +1 -0
- package/src/domains/auth/infrastructure/services/index.ts +16 -0
- package/src/domains/auth/infrastructure/services/utils/index.ts +1 -0
- package/src/domains/auth/infrastructure/stores/index.ts +1 -0
- package/src/domains/auth/infrastructure/utils/index.ts +1 -0
- package/src/domains/auth/infrastructure.ts +11 -0
- package/src/domains/auth/presentation/hooks/useGoogleOAuth.ts +18 -59
- package/src/domains/firestore/domain/entities/Collection.ts +0 -2
- package/src/domains/firestore/domain/index.ts +6 -2
- package/src/domains/firestore/domain/value-objects/WhereClause.ts +0 -14
- package/src/domains/firestore/index.ts +0 -1
- package/src/domains/firestore/infrastructure/config/FirestoreClient.ts +42 -60
- package/src/domains/firestore/presentation/hooks/useFirestoreMutation.ts +1 -1
- package/src/domains/firestore/presentation/hooks/useFirestoreQuery.ts +1 -1
- package/src/shared/infrastructure/base/ErrorHandler.ts +81 -0
- package/src/shared/infrastructure/base/ServiceBase.ts +62 -0
- package/src/shared/infrastructure/config/base/ServiceClientSingleton.ts +39 -0
- package/src/application/auth/ports/AuthPort.ts.bak +0 -164
- package/src/application/auth/ports/AuthPort_part_aa +0 -150
- package/src/application/auth/ports/AuthPort_part_ab +0 -14
- package/src/application/auth/use-cases/SignInUseCase.ts.bak +0 -253
- package/src/application/auth/use-cases/SignInUseCaseHelpers.ts +0 -0
- package/src/application/auth/use-cases/SignInUseCaseMain.ts +0 -0
- package/src/application/auth/use-cases/SignInUseCase_part_aa +0 -150
- package/src/application/auth/use-cases/SignInUseCase_part_ab +0 -103
- package/src/application/auth/use-cases/SignOutUseCase.ts.bak +0 -288
- package/src/application/auth/use-cases/SignOutUseCaseCleanup.ts +0 -0
- package/src/application/auth/use-cases/SignOutUseCaseMain.ts +0 -0
- package/src/application/auth/use-cases/SignOutUseCase_part_aa +0 -150
- package/src/application/auth/use-cases/SignOutUseCase_part_ab +0 -138
- package/src/domains/account-deletion/domain/services/UserValidationHelpers.ts.bak +0 -181
- package/src/domains/account-deletion/domain/services/UserValidationHelpers_part_aa +0 -150
- package/src/domains/account-deletion/domain/services/UserValidationHelpers_part_ab +0 -31
- package/src/domains/account-deletion/domain/services/UserValidationService.ts.bak +0 -286
- package/src/domains/account-deletion/domain/services/UserValidationService_part_aa +0 -150
- package/src/domains/account-deletion/domain/services/UserValidationService_part_ab +0 -136
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor.ts.bak +0 -230
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor_part_aa +0 -150
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor_part_ab +0 -80
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionReauthHandler.ts.bak +0 -174
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionReauthHandler_part_aa +0 -150
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionReauthHandler_part_ab +0 -24
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository.ts.bak +0 -266
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository_part_aa +0 -150
- package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository_part_ab +0 -116
- package/src/domains/account-deletion/infrastructure/services/reauthentication.service.ts.bak +0 -160
- package/src/domains/account-deletion/infrastructure/services/reauthentication.service_part_aa +0 -150
- package/src/domains/account-deletion/infrastructure/services/reauthentication.service_part_ab +0 -10
- package/src/domains/auth/infrastructure.ts.bak +0 -156
- package/src/domains/auth/infrastructure_part_aa +0 -150
- package/src/domains/auth/infrastructure_part_ab +0 -6
- package/src/domains/auth/presentation/hooks/GoogleOAuthHelpers.ts +0 -0
- package/src/domains/auth/presentation/hooks/GoogleOAuthHookService.ts.bak +0 -247
- package/src/domains/auth/presentation/hooks/GoogleOAuthHookService_part_aa +0 -150
- package/src/domains/auth/presentation/hooks/GoogleOAuthHookService_part_ab +0 -97
- package/src/domains/auth/presentation/hooks/GoogleOAuthService.ts +0 -0
- package/src/domains/firestore/domain/entities/Collection.ts.bak +0 -288
- package/src/domains/firestore/domain/entities/Collection_part_aa +0 -150
- package/src/domains/firestore/domain/entities/Collection_part_ab +0 -138
- package/src/domains/firestore/domain/entities/Document.ts.bak +0 -233
- package/src/domains/firestore/domain/entities/DocumentHelpers.ts +0 -0
- package/src/domains/firestore/domain/entities/DocumentMain.ts +0 -0
- package/src/domains/firestore/domain/entities/Document_part_aa +0 -150
- package/src/domains/firestore/domain/entities/Document_part_ab +0 -83
- package/src/domains/firestore/domain/services/QueryService.ts.bak +0 -182
- package/src/domains/firestore/domain/services/QueryServiceAnalysis.ts.bak +0 -169
- package/src/domains/firestore/domain/services/QueryServiceAnalysis_part_aa +0 -150
- package/src/domains/firestore/domain/services/QueryServiceAnalysis_part_ab +0 -19
- package/src/domains/firestore/domain/services/QueryServiceHelpers.ts.bak +0 -151
- package/src/domains/firestore/domain/services/QueryServiceHelpers_part_aa +0 -150
- package/src/domains/firestore/domain/services/QueryServiceHelpers_part_ab +0 -1
- package/src/domains/firestore/domain/services/QueryService_part_aa +0 -150
- package/src/domains/firestore/domain/services/QueryService_part_ab +0 -32
- package/src/domains/firestore/domain/value-objects/QueryOptions.ts.bak +0 -191
- package/src/domains/firestore/domain/value-objects/QueryOptionsSerialization.ts.bak +0 -207
- package/src/domains/firestore/domain/value-objects/QueryOptionsSerialization_part_aa +0 -150
- package/src/domains/firestore/domain/value-objects/QueryOptionsSerialization_part_ab +0 -57
- package/src/domains/firestore/domain/value-objects/QueryOptionsValidation.ts.bak +0 -182
- package/src/domains/firestore/domain/value-objects/QueryOptionsValidation_part_aa +0 -150
- package/src/domains/firestore/domain/value-objects/QueryOptionsValidation_part_ab +0 -32
- package/src/domains/firestore/domain/value-objects/QueryOptions_part_aa +0 -150
- package/src/domains/firestore/domain/value-objects/QueryOptions_part_ab +0 -41
- package/src/domains/firestore/domain/value-objects/WhereClause.ts.bak +0 -299
- package/src/domains/firestore/domain/value-objects/WhereClauseFactory.ts.bak +0 -207
- package/src/domains/firestore/domain/value-objects/WhereClauseFactory_part_aa +0 -150
- package/src/domains/firestore/domain/value-objects/WhereClauseFactory_part_ab +0 -57
- package/src/domains/firestore/domain/value-objects/WhereClause_part_aa +0 -150
- package/src/domains/firestore/domain/value-objects/WhereClause_part_ab +0 -149
- package/src/shared/infrastructure/base/ErrorHandler.ts.bak +0 -189
- package/src/shared/infrastructure/base/ErrorHandler_part_aa +0 -150
- package/src/shared/infrastructure/base/ErrorHandler_part_ab +0 -39
- package/src/shared/infrastructure/base/ServiceBase.ts.bak +0 -220
- package/src/shared/infrastructure/base/ServiceBase_part_aa +0 -150
- package/src/shared/infrastructure/base/ServiceBase_part_ab +0 -70
- package/src/shared/infrastructure/config/base/ServiceClientSingleton.ts.bak +0 -155
- package/src/shared/infrastructure/config/base/ServiceClientSingleton_part_aa +0 -150
- package/src/shared/infrastructure/config/base/ServiceClientSingleton_part_ab +0 -5
package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository_part_aa
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Account Deletion Repository
|
|
3
|
-
* Single Responsibility: Handle account deletion persistence
|
|
4
|
-
*
|
|
5
|
-
* Infrastructure repository that manages account deletion operations.
|
|
6
|
-
* Uses ServiceBase for error handling and initialization.
|
|
7
|
-
*
|
|
8
|
-
* Max lines: 150 (enforced for maintainability)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { deleteUser, type User } from 'firebase/auth';
|
|
12
|
-
import { ServiceBase } from '../../../../shared/infrastructure/base/ServiceBase';
|
|
13
|
-
import type { Result } from '../../../../shared/domain/utils';
|
|
14
|
-
import { successResult } from '../../../../shared/domain/utils';
|
|
15
|
-
import { markUserDeleted } from '../../../auth/infrastructure/services/user-document.service';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Account deletion repository
|
|
19
|
-
* Manages account deletion operations and user document cleanup
|
|
20
|
-
*/
|
|
21
|
-
export class AccountDeletionRepository extends ServiceBase {
|
|
22
|
-
constructor() {
|
|
23
|
-
super({
|
|
24
|
-
serviceName: 'AccountDeletionRepository',
|
|
25
|
-
autoInitialize: true,
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Delete user account from Firebase Auth
|
|
31
|
-
* Marks user document as deleted before account removal
|
|
32
|
-
*/
|
|
33
|
-
async deleteAccount(user: User): Promise<Result<void>> {
|
|
34
|
-
return this.execute(async () => {
|
|
35
|
-
this.log('Deleting account', { userId: user.uid });
|
|
36
|
-
|
|
37
|
-
// Mark user document as deleted
|
|
38
|
-
const marked = await markUserDeleted(user.uid);
|
|
39
|
-
if (!marked && __DEV__) {
|
|
40
|
-
this.logError('Failed to mark user document as deleted');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Delete user account
|
|
44
|
-
await deleteUser(user);
|
|
45
|
-
|
|
46
|
-
this.log('Account deleted successfully', { userId: user.uid });
|
|
47
|
-
}, 'account-deletion/delete-failed');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Validate user can be deleted
|
|
52
|
-
* Checks user is not anonymous and has valid provider
|
|
53
|
-
*/
|
|
54
|
-
async validateForDeletion(user: User | null): Promise<Result<{ userId: string; provider: string }>> {
|
|
55
|
-
return this.executeSync(() => {
|
|
56
|
-
if (!user) {
|
|
57
|
-
return {
|
|
58
|
-
success: false,
|
|
59
|
-
error: {
|
|
60
|
-
code: 'auth/not-ready',
|
|
61
|
-
message: 'No authenticated user',
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (user.isAnonymous) {
|
|
67
|
-
return {
|
|
68
|
-
success: false,
|
|
69
|
-
error: {
|
|
70
|
-
code: 'auth/anonymous',
|
|
71
|
-
message: 'Cannot delete anonymous account',
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const provider = this.getUserAuthProvider(user);
|
|
77
|
-
if (!provider) {
|
|
78
|
-
return {
|
|
79
|
-
success: false,
|
|
80
|
-
error: {
|
|
81
|
-
code: 'auth/unsupported',
|
|
82
|
-
message: 'Unsupported auth provider',
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return successResult({
|
|
88
|
-
userId: user.uid,
|
|
89
|
-
provider,
|
|
90
|
-
});
|
|
91
|
-
}, 'account-deletion/validation-failed');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Get user's auth provider
|
|
96
|
-
*/
|
|
97
|
-
private getUserAuthProvider(user: User): string | null {
|
|
98
|
-
if (!user.providerData || user.providerData.length === 0) {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
for (const userInfo of user.providerData) {
|
|
103
|
-
if (userInfo.providerId) {
|
|
104
|
-
return userInfo.providerId;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Check if user is email/password user
|
|
113
|
-
*/
|
|
114
|
-
isEmailPasswordUser(user: User): boolean {
|
|
115
|
-
return this.getUserAuthProvider(user) === 'password';
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Check if user is Google user
|
|
120
|
-
*/
|
|
121
|
-
isGoogleUser(user: User): boolean {
|
|
122
|
-
return this.getUserAuthProvider(user) === 'google.com';
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Check if user is Apple user
|
|
127
|
-
*/
|
|
128
|
-
isAppleUser(user: User): boolean {
|
|
129
|
-
return this.getUserAuthProvider(user) === 'apple.com';
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Get user ID from user object
|
|
134
|
-
*/
|
|
135
|
-
getUserId(user: User): string {
|
|
136
|
-
return user.uid;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Check if user email is verified
|
|
141
|
-
*/
|
|
142
|
-
isEmailVerified(user: User): boolean {
|
|
143
|
-
return user.emailVerified || false;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get user email
|
|
148
|
-
*/
|
|
149
|
-
getEmail(user: User): string | null {
|
|
150
|
-
return user.email || null;
|
package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository_part_ab
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
}
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Get account creation time
|
|
5
|
-
*/
|
|
6
|
-
getCreationTime(user: User): Date | null {
|
|
7
|
-
if (!user.metadata.creationTime) {
|
|
8
|
-
return null;
|
|
9
|
-
}
|
|
10
|
-
return new Date(user.metadata.creationTime);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Get last sign-in time
|
|
15
|
-
*/
|
|
16
|
-
getLastSignInTime(user: User): Date | null {
|
|
17
|
-
if (!user.metadata.lastSignInTime) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
return new Date(user.metadata.lastSignInTime);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Check if account is new (created within specified days)
|
|
25
|
-
*/
|
|
26
|
-
isAccountNew(user: User, maxAgeDays: number = 1): boolean {
|
|
27
|
-
const creationTime = this.getCreationTime(user);
|
|
28
|
-
if (!creationTime) return false;
|
|
29
|
-
|
|
30
|
-
const ageMs = Date.now() - creationTime.getTime();
|
|
31
|
-
const maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1000;
|
|
32
|
-
|
|
33
|
-
return ageMs <= maxAgeMs;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Check if user recently signed in
|
|
38
|
-
*/
|
|
39
|
-
isRecentSignIn(user: User, maxAgeMinutes: number = 5): boolean {
|
|
40
|
-
const lastSignIn = this.getLastSignInTime(user);
|
|
41
|
-
if (!lastSignIn) return false;
|
|
42
|
-
|
|
43
|
-
const timeSinceSignIn = Date.now() - lastSignIn.getTime();
|
|
44
|
-
const maxAgeMs = maxAgeMinutes * 60 * 1000;
|
|
45
|
-
|
|
46
|
-
return timeSinceSignIn <= maxAgeMs;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Mark user as deleted in database
|
|
51
|
-
* Separate method for flexibility
|
|
52
|
-
*/
|
|
53
|
-
async markUserDeleted(userId: string): Promise<Result<void>> {
|
|
54
|
-
return this.execute(async () => {
|
|
55
|
-
this.log('Marking user as deleted', { userId });
|
|
56
|
-
|
|
57
|
-
const marked = await markUserDeleted(userId);
|
|
58
|
-
if (!marked) {
|
|
59
|
-
this.logError('Failed to mark user as deleted in database');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return successResult();
|
|
63
|
-
}, 'account-deletion/mark-failed');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Cleanup user data
|
|
68
|
-
* Override in subclass for custom cleanup logic
|
|
69
|
-
*/
|
|
70
|
-
protected async cleanupUserData(userId: string): Promise<Result<void>> {
|
|
71
|
-
return this.execute(async () => {
|
|
72
|
-
this.log('Cleaning up user data', { userId });
|
|
73
|
-
// Override in subclass for custom cleanup
|
|
74
|
-
return successResult();
|
|
75
|
-
}, 'account-deletion/cleanup-failed');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Complete deletion with cleanup
|
|
80
|
-
* Deletes account and cleans up user data
|
|
81
|
-
*/
|
|
82
|
-
async deleteWithCleanup(user: User): Promise<Result<void>> {
|
|
83
|
-
return this.execute(async () => {
|
|
84
|
-
this.log('Starting deletion with cleanup', { userId: user.uid });
|
|
85
|
-
|
|
86
|
-
// Delete account (includes marking document as deleted)
|
|
87
|
-
const deleteResult = await this.deleteAccount(user);
|
|
88
|
-
if (!deleteResult.success) {
|
|
89
|
-
return deleteResult;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Cleanup additional user data
|
|
93
|
-
const cleanupResult = await this.cleanupUserData(user.uid);
|
|
94
|
-
if (!cleanupResult.success) {
|
|
95
|
-
this.logError('Cleanup failed, but account was deleted', {
|
|
96
|
-
userId: user.uid,
|
|
97
|
-
error: cleanupResult.error,
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
this.log('Deletion with cleanup completed', { userId: user.uid });
|
|
102
|
-
}, 'account-deletion/complete-failed');
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Factory function to create account deletion repository
|
|
108
|
-
*/
|
|
109
|
-
export function createAccountDeletionRepository(): AccountDeletionRepository {
|
|
110
|
-
return new AccountDeletionRepository();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Default singleton instance
|
|
115
|
-
*/
|
|
116
|
-
export const accountDeletionRepository = createAccountDeletionRepository();
|
package/src/domains/account-deletion/infrastructure/services/reauthentication.service.ts.bak
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reauthentication Service
|
|
3
|
-
* Handles Firebase Auth reauthentication for sensitive operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
reauthenticateWithCredential,
|
|
8
|
-
GoogleAuthProvider,
|
|
9
|
-
OAuthProvider,
|
|
10
|
-
EmailAuthProvider,
|
|
11
|
-
type User,
|
|
12
|
-
} from "firebase/auth";
|
|
13
|
-
import { Platform } from "react-native";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Lazy-loads expo-apple-authentication (optional peer dependency).
|
|
17
|
-
* Returns null if the package is not installed.
|
|
18
|
-
*/
|
|
19
|
-
function getAppleAuthModule(): typeof import("expo-apple-authentication") | null {
|
|
20
|
-
try {
|
|
21
|
-
// Dynamic require needed for optional peer dependency
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
23
|
-
return require("expo-apple-authentication");
|
|
24
|
-
} catch {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
import { generateNonce, hashNonce } from "../../../auth/infrastructure/services/crypto.util";
|
|
29
|
-
import { executeOperation, failureResultFrom, toErrorInfo, ERROR_MESSAGES } from "../../../../shared/domain/utils";
|
|
30
|
-
import { isCancelledError } from "../../../../shared/domain/utils/error-handlers/error-checkers";
|
|
31
|
-
import type {
|
|
32
|
-
ReauthenticationResult,
|
|
33
|
-
AuthProviderType,
|
|
34
|
-
ReauthCredentialResult
|
|
35
|
-
} from "../../application/ports/reauthentication.types";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Validates email format
|
|
39
|
-
*/
|
|
40
|
-
function isValidEmail(email: string): boolean {
|
|
41
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
42
|
-
return emailRegex.test(email);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Validates password (Firebase minimum is 6 characters)
|
|
47
|
-
*/
|
|
48
|
-
function isValidPassword(password: string): boolean {
|
|
49
|
-
return password.length >= 6;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function getUserAuthProvider(user: User): AuthProviderType {
|
|
53
|
-
if (user.isAnonymous) return "anonymous";
|
|
54
|
-
const data = user.providerData;
|
|
55
|
-
if (!data?.length) return "unknown";
|
|
56
|
-
if (data.find(p => p.providerId === "google.com")) return "google.com";
|
|
57
|
-
if (data.find(p => p.providerId === "apple.com")) return "apple.com";
|
|
58
|
-
if (data.find(p => p.providerId === "password")) return "password";
|
|
59
|
-
return "unknown";
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export async function reauthenticateWithGoogle(user: User, idToken: string): Promise<ReauthenticationResult> {
|
|
63
|
-
return executeOperation(async () => {
|
|
64
|
-
await reauthenticateWithCredential(user, GoogleAuthProvider.credential(idToken));
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function reauthenticateWithPassword(user: User, pass: string): Promise<ReauthenticationResult> {
|
|
69
|
-
const email = user.email;
|
|
70
|
-
if (!email) {
|
|
71
|
-
return failureResultFrom("auth/no-email", ERROR_MESSAGES.AUTH.NO_USER);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// FIX: Add email validation
|
|
75
|
-
if (!isValidEmail(email)) {
|
|
76
|
-
return failureResultFrom("auth/invalid-email", ERROR_MESSAGES.AUTH.INVALID_EMAIL);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// FIX: Add password validation
|
|
80
|
-
if (!isValidPassword(pass)) {
|
|
81
|
-
return failureResultFrom("auth/invalid-password", ERROR_MESSAGES.AUTH.INVALID_PASSWORD);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return executeOperation(async () => {
|
|
85
|
-
await reauthenticateWithCredential(user, EmailAuthProvider.credential(email, pass));
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export async function getAppleReauthCredential(): Promise<ReauthCredentialResult> {
|
|
90
|
-
if (Platform.OS !== "ios") {
|
|
91
|
-
return {
|
|
92
|
-
success: false,
|
|
93
|
-
error: { code: "auth/ios-only", message: "iOS only" }
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const AppleAuthentication = getAppleAuthModule();
|
|
98
|
-
if (!AppleAuthentication) {
|
|
99
|
-
return {
|
|
100
|
-
success: false,
|
|
101
|
-
error: { code: "auth/unavailable", message: "expo-apple-authentication is not installed" }
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
const isAvailable = await AppleAuthentication.isAvailableAsync();
|
|
107
|
-
if (!isAvailable) {
|
|
108
|
-
return {
|
|
109
|
-
success: false,
|
|
110
|
-
error: { code: "auth/unavailable", message: "Unavailable" }
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const nonce = await generateNonce();
|
|
115
|
-
const hashed = await hashNonce(nonce);
|
|
116
|
-
const apple = await AppleAuthentication.signInAsync({
|
|
117
|
-
requestedScopes: [
|
|
118
|
-
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
|
|
119
|
-
AppleAuthentication.AppleAuthenticationScope.EMAIL
|
|
120
|
-
],
|
|
121
|
-
nonce: hashed,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
if (!apple.identityToken) {
|
|
125
|
-
return {
|
|
126
|
-
success: false,
|
|
127
|
-
error: { code: "auth/no-token", message: "No token" }
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const credential = new OAuthProvider("apple.com").credential({
|
|
132
|
-
idToken: apple.identityToken,
|
|
133
|
-
rawNonce: nonce
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
success: true,
|
|
138
|
-
credential
|
|
139
|
-
};
|
|
140
|
-
} catch (error: unknown) {
|
|
141
|
-
const errorInfo = toErrorInfo(error, 'auth/failed');
|
|
142
|
-
const code = isCancelledError(errorInfo) ? "auth/cancelled" : errorInfo.code;
|
|
143
|
-
return {
|
|
144
|
-
success: false,
|
|
145
|
-
error: { code, message: errorInfo.message }
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export async function reauthenticateWithApple(user: User): Promise<ReauthenticationResult> {
|
|
151
|
-
const res = await getAppleReauthCredential();
|
|
152
|
-
if (!res.success || !res.credential) {
|
|
153
|
-
return { success: false, error: res.error ?? { code: "auth/failed", message: "Failed to get credential" } };
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const credential = res.credential;
|
|
157
|
-
return executeOperation(async () => {
|
|
158
|
-
await reauthenticateWithCredential(user, credential);
|
|
159
|
-
});
|
|
160
|
-
}
|
package/src/domains/account-deletion/infrastructure/services/reauthentication.service_part_aa
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reauthentication Service
|
|
3
|
-
* Handles Firebase Auth reauthentication for sensitive operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
reauthenticateWithCredential,
|
|
8
|
-
GoogleAuthProvider,
|
|
9
|
-
OAuthProvider,
|
|
10
|
-
EmailAuthProvider,
|
|
11
|
-
type User,
|
|
12
|
-
} from "firebase/auth";
|
|
13
|
-
import { Platform } from "react-native";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Lazy-loads expo-apple-authentication (optional peer dependency).
|
|
17
|
-
* Returns null if the package is not installed.
|
|
18
|
-
*/
|
|
19
|
-
function getAppleAuthModule(): typeof import("expo-apple-authentication") | null {
|
|
20
|
-
try {
|
|
21
|
-
// Dynamic require needed for optional peer dependency
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
23
|
-
return require("expo-apple-authentication");
|
|
24
|
-
} catch {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
import { generateNonce, hashNonce } from "../../../auth/infrastructure/services/crypto.util";
|
|
29
|
-
import { executeOperation, failureResultFrom, toErrorInfo, ERROR_MESSAGES } from "../../../../shared/domain/utils";
|
|
30
|
-
import { isCancelledError } from "../../../../shared/domain/utils/error-handlers/error-checkers";
|
|
31
|
-
import type {
|
|
32
|
-
ReauthenticationResult,
|
|
33
|
-
AuthProviderType,
|
|
34
|
-
ReauthCredentialResult
|
|
35
|
-
} from "../../application/ports/reauthentication.types";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Validates email format
|
|
39
|
-
*/
|
|
40
|
-
function isValidEmail(email: string): boolean {
|
|
41
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
42
|
-
return emailRegex.test(email);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Validates password (Firebase minimum is 6 characters)
|
|
47
|
-
*/
|
|
48
|
-
function isValidPassword(password: string): boolean {
|
|
49
|
-
return password.length >= 6;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function getUserAuthProvider(user: User): AuthProviderType {
|
|
53
|
-
if (user.isAnonymous) return "anonymous";
|
|
54
|
-
const data = user.providerData;
|
|
55
|
-
if (!data?.length) return "unknown";
|
|
56
|
-
if (data.find(p => p.providerId === "google.com")) return "google.com";
|
|
57
|
-
if (data.find(p => p.providerId === "apple.com")) return "apple.com";
|
|
58
|
-
if (data.find(p => p.providerId === "password")) return "password";
|
|
59
|
-
return "unknown";
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export async function reauthenticateWithGoogle(user: User, idToken: string): Promise<ReauthenticationResult> {
|
|
63
|
-
return executeOperation(async () => {
|
|
64
|
-
await reauthenticateWithCredential(user, GoogleAuthProvider.credential(idToken));
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function reauthenticateWithPassword(user: User, pass: string): Promise<ReauthenticationResult> {
|
|
69
|
-
const email = user.email;
|
|
70
|
-
if (!email) {
|
|
71
|
-
return failureResultFrom("auth/no-email", ERROR_MESSAGES.AUTH.NO_USER);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// FIX: Add email validation
|
|
75
|
-
if (!isValidEmail(email)) {
|
|
76
|
-
return failureResultFrom("auth/invalid-email", ERROR_MESSAGES.AUTH.INVALID_EMAIL);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// FIX: Add password validation
|
|
80
|
-
if (!isValidPassword(pass)) {
|
|
81
|
-
return failureResultFrom("auth/invalid-password", ERROR_MESSAGES.AUTH.INVALID_PASSWORD);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return executeOperation(async () => {
|
|
85
|
-
await reauthenticateWithCredential(user, EmailAuthProvider.credential(email, pass));
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export async function getAppleReauthCredential(): Promise<ReauthCredentialResult> {
|
|
90
|
-
if (Platform.OS !== "ios") {
|
|
91
|
-
return {
|
|
92
|
-
success: false,
|
|
93
|
-
error: { code: "auth/ios-only", message: "iOS only" }
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const AppleAuthentication = getAppleAuthModule();
|
|
98
|
-
if (!AppleAuthentication) {
|
|
99
|
-
return {
|
|
100
|
-
success: false,
|
|
101
|
-
error: { code: "auth/unavailable", message: "expo-apple-authentication is not installed" }
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
const isAvailable = await AppleAuthentication.isAvailableAsync();
|
|
107
|
-
if (!isAvailable) {
|
|
108
|
-
return {
|
|
109
|
-
success: false,
|
|
110
|
-
error: { code: "auth/unavailable", message: "Unavailable" }
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const nonce = await generateNonce();
|
|
115
|
-
const hashed = await hashNonce(nonce);
|
|
116
|
-
const apple = await AppleAuthentication.signInAsync({
|
|
117
|
-
requestedScopes: [
|
|
118
|
-
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
|
|
119
|
-
AppleAuthentication.AppleAuthenticationScope.EMAIL
|
|
120
|
-
],
|
|
121
|
-
nonce: hashed,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
if (!apple.identityToken) {
|
|
125
|
-
return {
|
|
126
|
-
success: false,
|
|
127
|
-
error: { code: "auth/no-token", message: "No token" }
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const credential = new OAuthProvider("apple.com").credential({
|
|
132
|
-
idToken: apple.identityToken,
|
|
133
|
-
rawNonce: nonce
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
success: true,
|
|
138
|
-
credential
|
|
139
|
-
};
|
|
140
|
-
} catch (error: unknown) {
|
|
141
|
-
const errorInfo = toErrorInfo(error, 'auth/failed');
|
|
142
|
-
const code = isCancelledError(errorInfo) ? "auth/cancelled" : errorInfo.code;
|
|
143
|
-
return {
|
|
144
|
-
success: false,
|
|
145
|
-
error: { code, message: errorInfo.message }
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export async function reauthenticateWithApple(user: User): Promise<ReauthenticationResult> {
|
package/src/domains/account-deletion/infrastructure/services/reauthentication.service_part_ab
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
const res = await getAppleReauthCredential();
|
|
2
|
-
if (!res.success || !res.credential) {
|
|
3
|
-
return { success: false, error: res.error ?? { code: "auth/failed", message: "Failed to get credential" } };
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
const credential = res.credential;
|
|
7
|
-
return executeOperation(async () => {
|
|
8
|
-
await reauthenticateWithCredential(user, credential);
|
|
9
|
-
});
|
|
10
|
-
}
|