From 5d155e25dbb31e13322b63ec2544af18b948c290 Mon Sep 17 00:00:00 2001 From: opficdev Date: Wed, 11 Mar 2026 12:42:22 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20=EC=97=AC=EB=9F=AC=20=EA=B3=B5?= =?UTF-8?q?=EA=B8=89=EC=9E=90=EA=B0=80=20=EB=A7=81=ED=81=AC=EB=90=9C=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20providers?= =?UTF-8?q?=EB=A5=BC=20=EC=88=9C=ED=9A=8C=ED=95=B4=EC=84=9C=20=EB=A7=81?= =?UTF-8?q?=ED=81=AC=EB=A5=BC=20=EB=81=89=EB=8F=84=EB=A1=9D=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuthenticationRepositoryImpl.swift | 27 ++++++++++------- DevLog/Infra/Service/AuthService.swift | 29 +++++++++++++++++++ .../AppleAuthenticationService.swift | 8 ----- .../GithubAuthenticationService.swift | 8 ----- .../GoogleAuthenticationService.swift | 7 ----- 5 files changed, 45 insertions(+), 34 deletions(-) diff --git a/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift b/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift index 54fc5681..05c62095 100644 --- a/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift +++ b/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift @@ -63,20 +63,25 @@ final class AuthenticationRepositoryImpl: AuthenticationRepository { } func delete() async throws { - guard let uid = authService.uid, - let providerID = try await authService.getProviderID(), - let provider = AuthProvider(rawValue: providerID) - else { + guard let uid = authService.uid else { throw AuthError.notAuthenticated } - switch provider { - case .apple: - try await appleAuthService.deleteAuth(uid) - case .github: - try await githubAuthService.deleteAuth(uid) - case .google: - try await googleAuthService.deleteAuth(uid) + let providers = (authService.providerIDs ?? []).compactMap { AuthProvider(rawValue: $0) } + + for provider in providers { + switch provider { + case .apple: + try await appleAuthService.deleteAuth(uid) + case .github: + try await githubAuthService.deleteAuth(uid) + case .google: + try await googleAuthService.deleteAuth(uid) + } } + + try await authService.deleteFirestoreUserData(uid) + try await authService.deleteCurrentUser() + try await authService.clearCurrentSession() } } diff --git a/DevLog/Infra/Service/AuthService.swift b/DevLog/Infra/Service/AuthService.swift index c47e5645..0387d3e5 100644 --- a/DevLog/Infra/Service/AuthService.swift +++ b/DevLog/Infra/Service/AuthService.swift @@ -7,9 +7,13 @@ import FirebaseAuth import FirebaseFirestore +import FirebaseFunctions +import FirebaseMessaging final class AuthService { private let store = Firestore.firestore() + private let functions = Functions.functions(region: "asia-northeast3") + private let messaging = Messaging.messaging() private let logger = Logger(category: "AuthService") var uid: String? { @@ -42,4 +46,29 @@ final class AuthService { throw error } } + + func deleteFirestoreUserData(_ uid: String) async throws { + logger.info("Deleting Firestore user data. uid: \(uid)") + + let deleteFunction = functions.httpsCallable("deleteUserFirestoreData") + _ = try await deleteFunction.call(["uid": uid]) + } + + func deleteCurrentUser() async throws { + logger.info("Deleting FirebaseAuth current user") + + guard let currentUser = Auth.auth().currentUser else { + logger.warning("No current user to delete") + throw AuthError.notAuthenticated + } + + try await currentUser.delete() + } + + func clearCurrentSession() async throws { + logger.info("Clearing current auth session") + + try await messaging.deleteToken() + try Auth.auth().signOut() + } } diff --git a/DevLog/Infra/Service/SocialLogin/AppleAuthenticationService.swift b/DevLog/Infra/Service/SocialLogin/AppleAuthenticationService.swift index 635131df..19b9f5cd 100644 --- a/DevLog/Infra/Service/SocialLogin/AppleAuthenticationService.swift +++ b/DevLog/Infra/Service/SocialLogin/AppleAuthenticationService.swift @@ -105,14 +105,6 @@ final class AppleAuthenticationService: AuthenticationService { let token = try await refreshAppleAccessToken() try await revokeAppleAccessToken(token: token) - - let deleteFunction = functions.httpsCallable("deleteUserFirestoreData") - - _ = try await deleteFunction.call(["uid": uid]) - - try await user?.delete() - try await messaging.deleteToken() - try Auth.auth().signOut() } func link(uid: String, email: String) async throws { diff --git a/DevLog/Infra/Service/SocialLogin/GithubAuthenticationService.swift b/DevLog/Infra/Service/SocialLogin/GithubAuthenticationService.swift index d9aeaa20..77265ac1 100644 --- a/DevLog/Infra/Service/SocialLogin/GithubAuthenticationService.swift +++ b/DevLog/Infra/Service/SocialLogin/GithubAuthenticationService.swift @@ -82,14 +82,6 @@ final class GithubAuthenticationService: NSObject, AuthenticationService { func deleteAuth(_ uid: String) async throws { try await revokeAccessToken() - - let deleteFunction = functions.httpsCallable("deleteUserFirestoreData") - - _ = try await deleteFunction.call(["uid": uid]) - - try await user?.delete() - try await messaging.deleteToken() - try Auth.auth().signOut() } func link(uid: String, email: String) async throws { diff --git a/DevLog/Infra/Service/SocialLogin/GoogleAuthenticationService.swift b/DevLog/Infra/Service/SocialLogin/GoogleAuthenticationService.swift index 3fb15f44..0d094154 100644 --- a/DevLog/Infra/Service/SocialLogin/GoogleAuthenticationService.swift +++ b/DevLog/Infra/Service/SocialLogin/GoogleAuthenticationService.swift @@ -78,15 +78,8 @@ final class GoogleAuthenticationService: AuthenticationService { } func deleteAuth(_ uid: String) async throws { - let deleteFunction = functions.httpsCallable("deleteUserFirestoreData") - - _ = try await deleteFunction.call(["uid": uid]) - - try await user?.delete() GIDSignIn.sharedInstance.signOut() try await GIDSignIn.sharedInstance.disconnect() - try await messaging.deleteToken() - try Auth.auth().signOut() } func link(uid: String, email: String) async throws { From 81f0c999cb35e987824234e725f9faeb4404ab99 Mon Sep 17 00:00:00 2001 From: opficdev Date: Wed, 11 Mar 2026 12:44:39 +0900 Subject: [PATCH 2/4] =?UTF-8?q?refactor:=20providerIDs=EA=B0=80=20currentU?= =?UTF-8?q?ser=EA=B0=80=20nil=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20=EB=B9=88=20?= =?UTF-8?q?=EB=B0=B0=EC=97=B4=EC=9D=84=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DevLog/Data/Repository/AuthDataRepositoryImpl.swift | 2 +- DevLog/Data/Repository/AuthenticationRepositoryImpl.swift | 2 +- DevLog/Infra/Service/AuthService.swift | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DevLog/Data/Repository/AuthDataRepositoryImpl.swift b/DevLog/Data/Repository/AuthDataRepositoryImpl.swift index e580a044..47eb308d 100644 --- a/DevLog/Data/Repository/AuthDataRepositoryImpl.swift +++ b/DevLog/Data/Repository/AuthDataRepositoryImpl.swift @@ -33,7 +33,7 @@ final class AuthDataRepositoryImpl: AuthDataRepository { } func fetchAllProviders() async throws -> [AuthProvider] { - let providerStrings = authService.providerIDs ?? [] + let providerStrings = authService.providerIDs return providerStrings.compactMap { AuthProvider(rawValue: $0) } } diff --git a/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift b/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift index 05c62095..f5e92e6b 100644 --- a/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift +++ b/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift @@ -67,7 +67,7 @@ final class AuthenticationRepositoryImpl: AuthenticationRepository { throw AuthError.notAuthenticated } - let providers = (authService.providerIDs ?? []).compactMap { AuthProvider(rawValue: $0) } + let providers = authService.providerIDs.compactMap { AuthProvider(rawValue: $0) } for provider in providers { switch provider { diff --git a/DevLog/Infra/Service/AuthService.swift b/DevLog/Infra/Service/AuthService.swift index 0387d3e5..a0334f96 100644 --- a/DevLog/Infra/Service/AuthService.swift +++ b/DevLog/Infra/Service/AuthService.swift @@ -20,8 +20,8 @@ final class AuthService { Auth.auth().currentUser?.uid } - var providerIDs: [String]? { - Auth.auth().currentUser?.providerData.map { $0.providerID } + var providerIDs: [String] { + Auth.auth().currentUser?.providerData.map { $0.providerID } ?? [] } func getProviderID() async throws -> String? { From 77fbb2379e2bd5dc2848cdfdddbee1869fdc27ca Mon Sep 17 00:00:00 2001 From: opficdev Date: Wed, 11 Mar 2026 12:57:23 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20uid=EB=A5=BC=20=ED=81=B4?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EC=96=B8=ED=8A=B8=20=EC=AA=BD=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=B3=B4=EB=82=B4=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repository/AuthenticationRepositoryImpl.swift | 2 +- DevLog/Infra/Service/AuthService.swift | 6 +++--- Firebase/functions/src/user/delete.ts | 12 +++++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift b/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift index f5e92e6b..ebb1b651 100644 --- a/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift +++ b/DevLog/Data/Repository/AuthenticationRepositoryImpl.swift @@ -80,7 +80,7 @@ final class AuthenticationRepositoryImpl: AuthenticationRepository { } } - try await authService.deleteFirestoreUserData(uid) + try await authService.deleteFirestoreUserData() try await authService.deleteCurrentUser() try await authService.clearCurrentSession() } diff --git a/DevLog/Infra/Service/AuthService.swift b/DevLog/Infra/Service/AuthService.swift index a0334f96..4d083bd2 100644 --- a/DevLog/Infra/Service/AuthService.swift +++ b/DevLog/Infra/Service/AuthService.swift @@ -47,11 +47,11 @@ final class AuthService { } } - func deleteFirestoreUserData(_ uid: String) async throws { - logger.info("Deleting Firestore user data. uid: \(uid)") + func deleteFirestoreUserData() async throws { + logger.info("Deleting Firestore user data") let deleteFunction = functions.httpsCallable("deleteUserFirestoreData") - _ = try await deleteFunction.call(["uid": uid]) + _ = try await deleteFunction.call() } func deleteCurrentUser() async throws { diff --git a/Firebase/functions/src/user/delete.ts b/Firebase/functions/src/user/delete.ts index 0ca9dfd2..80ee4d98 100644 --- a/Firebase/functions/src/user/delete.ts +++ b/Firebase/functions/src/user/delete.ts @@ -1,5 +1,6 @@ import { onCall, HttpsError } from "firebase-functions/v2/https"; import * as admin from "firebase-admin"; +import * as logger from "firebase-functions/logger"; export const deleteUserFirestoreData = onCall({ cors: true, @@ -7,9 +8,14 @@ export const deleteUserFirestoreData = onCall({ region: "asia-northeast3" }, async (request) => { - if (!request.auth) throw new HttpsError("unauthenticated", "로그인 필요"); - const uid = request.data.uid; - if (!uid) throw new HttpsError("invalid-argument", "uid 필요"); + if (!request.auth?.uid) { + logger.error("deleteUserFirestoreData called without authenticated uid", { + auth: request.auth ?? null + }); + throw new HttpsError("unauthenticated", "로그인 필요"); + } + + const uid = request.auth.uid; try { const userDocRef = admin.firestore().doc(`users/${uid}`); From 21a6518fb0d73d04a8eb265a1c38d93119d70767 Mon Sep 17 00:00:00 2001 From: opficdev Date: Wed, 11 Mar 2026 13:00:42 +0900 Subject: [PATCH 4/4] =?UTF-8?q?refactor:=20FCM=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=EC=9D=84=20=EC=82=AD=EC=A0=9C=ED=95=98=EB=8A=94=EB=8D=B0=20?= =?UTF-8?q?=EC=8B=A4=ED=8C=A8=ED=95=B4=EB=8F=84=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=95=84=EC=9B=83=EC=9D=80=20=EB=90=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DevLog/Infra/Service/AuthService.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DevLog/Infra/Service/AuthService.swift b/DevLog/Infra/Service/AuthService.swift index 4d083bd2..1368e8df 100644 --- a/DevLog/Infra/Service/AuthService.swift +++ b/DevLog/Infra/Service/AuthService.swift @@ -68,7 +68,11 @@ final class AuthService { func clearCurrentSession() async throws { logger.info("Clearing current auth session") - try await messaging.deleteToken() + do { + try await messaging.deleteToken() + } catch { + logger.error("Failed to delete FCM token while clearing session", error: error) + } try Auth.auth().signOut() } }