strapi-plugin-firebase-authentication 1.1.8 → 1.1.10
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/dist/_chunks/{App-Dt8F60Rl.mjs → App-Beg-rhfs.mjs} +124 -122
- package/dist/_chunks/{App-C_pWLYYH.js → App-Cd5yIsKz.js} +124 -122
- package/dist/_chunks/{api-T8QRCile.mjs → api-BznQNKgc.mjs} +1 -1
- package/dist/_chunks/{api-CxfueBVM.js → api-C7A4Ky3o.js} +1 -1
- package/dist/_chunks/{index-BzSU0Li9.mjs → index-C3713gpv.mjs} +1 -1
- package/dist/_chunks/{index-Do9Y0scX.mjs → index-Dxg4gNu5.mjs} +2 -2
- package/dist/_chunks/{index-BIHS9XB4.js → index-Dz1nqS7B.js} +2 -2
- package/dist/_chunks/{index-C87l6qcA.js → index-d4XkRCYN.js} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +185 -66
- package/dist/server/index.mjs +185 -66
- package/dist/server/src/controllers/firebaseController.d.ts +0 -1
- package/dist/server/src/controllers/index.d.ts +0 -1
- package/dist/server/src/index.d.ts +5 -6
- package/dist/server/src/services/firebaseService.d.ts +3 -3
- package/dist/server/src/services/index.d.ts +5 -5
- package/dist/server/src/services/settingsService.d.ts +1 -2
- package/dist/server/src/services/userService.d.ts +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -199,8 +199,8 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
199
199
|
}
|
|
200
200
|
} catch (error2) {
|
|
201
201
|
strapi2.log.error("Firebase initialization failed during bootstrap:");
|
|
202
|
-
strapi2.log.error(
|
|
203
|
-
strapi2.log.error(
|
|
202
|
+
strapi2.log.error(` Error: ${error2.message}`);
|
|
203
|
+
strapi2.log.error(` Stack: ${error2.stack}`);
|
|
204
204
|
}
|
|
205
205
|
await strapi2.admin.services.permission.actionProvider.registerMany(actions);
|
|
206
206
|
if (strapi2.plugin("users-permissions")) {
|
|
@@ -210,14 +210,14 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
210
210
|
if (process.env.RUN_FIREBASE_MIGRATION === "true") {
|
|
211
211
|
const dryRun = process.env.DRY_RUN === "true";
|
|
212
212
|
strapi2.log.info("");
|
|
213
|
-
strapi2.log.info("
|
|
213
|
+
strapi2.log.info("Firebase migration triggered by RUN_FIREBASE_MIGRATION env variable");
|
|
214
214
|
await migrateFirebaseUserData(strapi2, dryRun);
|
|
215
215
|
}
|
|
216
216
|
setImmediate(async () => {
|
|
217
217
|
try {
|
|
218
218
|
await strapi2.plugin("firebase-authentication").service("autoLinkService").linkAllUsers(strapi2);
|
|
219
219
|
} catch (error2) {
|
|
220
|
-
strapi2.log.error(
|
|
220
|
+
strapi2.log.error(`Auto-linking failed: ${error2.message}`);
|
|
221
221
|
}
|
|
222
222
|
});
|
|
223
223
|
};
|
|
@@ -442,7 +442,7 @@ const firebaseController = {
|
|
|
442
442
|
const result = await strapi.plugin(pluginName).service("firebaseService").validateFirebaseToken(idToken, profileMetaData, populate2);
|
|
443
443
|
ctx.body = result;
|
|
444
444
|
} catch (error2) {
|
|
445
|
-
strapi.log.error(
|
|
445
|
+
strapi.log.error(`validateToken controller error: ${error2.message}`);
|
|
446
446
|
if (error2.name === "ValidationError") {
|
|
447
447
|
return ctx.badRequest(error2.message);
|
|
448
448
|
}
|
|
@@ -452,9 +452,6 @@ const firebaseController = {
|
|
|
452
452
|
throw error2;
|
|
453
453
|
}
|
|
454
454
|
},
|
|
455
|
-
async createAlias(ctx) {
|
|
456
|
-
ctx.body = await strapi.plugin(pluginName).service("firebaseService").createAlias(ctx);
|
|
457
|
-
},
|
|
458
455
|
async deleteByEmail(email2) {
|
|
459
456
|
const user = await strapi.firebase.auth().getUserByEmail(email2);
|
|
460
457
|
await strapi.plugin(pluginName).service("firebaseService").delete(user.toJSON().uid);
|
|
@@ -518,7 +515,8 @@ const firebaseController = {
|
|
|
518
515
|
async forgotPassword(ctx) {
|
|
519
516
|
strapi.log.debug("forgotPassword endpoint called");
|
|
520
517
|
try {
|
|
521
|
-
ctx.body
|
|
518
|
+
const { email: email2 } = ctx.request.body || {};
|
|
519
|
+
ctx.body = await strapi.plugin(pluginName).service("firebaseService").forgotPassword(email2);
|
|
522
520
|
} catch (error2) {
|
|
523
521
|
strapi.log.error("forgotPassword controller error:", error2);
|
|
524
522
|
if (error2.name === "ValidationError") {
|
|
@@ -541,7 +539,10 @@ const firebaseController = {
|
|
|
541
539
|
async resetPassword(ctx) {
|
|
542
540
|
strapi.log.debug("resetPassword endpoint called");
|
|
543
541
|
try {
|
|
544
|
-
ctx.body
|
|
542
|
+
const { password } = ctx.request.body || {};
|
|
543
|
+
const token = ctx.request.headers.authorization?.replace("Bearer ", "");
|
|
544
|
+
const populate2 = ctx.request.query.populate || [];
|
|
545
|
+
ctx.body = await strapi.plugin(pluginName).service("firebaseService").resetPassword(password, token, populate2);
|
|
545
546
|
} catch (error2) {
|
|
546
547
|
strapi.log.error("resetPassword controller error:", error2);
|
|
547
548
|
if (error2.name === "ValidationError" || error2.name === "UnauthorizedError") {
|
|
@@ -554,7 +555,8 @@ const firebaseController = {
|
|
|
554
555
|
},
|
|
555
556
|
async requestMagicLink(ctx) {
|
|
556
557
|
try {
|
|
557
|
-
const
|
|
558
|
+
const { email: email2 } = ctx.request.body || {};
|
|
559
|
+
const result = await strapi.plugin("firebase-authentication").service("firebaseService").requestMagicLink(email2);
|
|
558
560
|
ctx.body = result;
|
|
559
561
|
} catch (error2) {
|
|
560
562
|
if (error2.name === "ValidationError" || error2.name === "ApplicationError") {
|
|
@@ -28937,11 +28939,12 @@ const userController = {
|
|
|
28937
28939
|
};
|
|
28938
28940
|
const settingsController = {
|
|
28939
28941
|
setFirebaseConfigJson: async (ctx) => {
|
|
28940
|
-
|
|
28942
|
+
const requestBody = ctx.request.body;
|
|
28943
|
+
ctx.body = await strapi.plugin("firebase-authentication").service("settingsService").setFirebaseConfigJson(requestBody);
|
|
28941
28944
|
},
|
|
28942
28945
|
getFirebaseConfigJson: async (ctx) => {
|
|
28943
28946
|
try {
|
|
28944
|
-
const config2 = await strapi.plugin("firebase-authentication").service("settingsService").getFirebaseConfigJson(
|
|
28947
|
+
const config2 = await strapi.plugin("firebase-authentication").service("settingsService").getFirebaseConfigJson();
|
|
28945
28948
|
if (!config2) {
|
|
28946
28949
|
return ctx.send(null);
|
|
28947
28950
|
}
|
|
@@ -28954,7 +28957,7 @@ const settingsController = {
|
|
|
28954
28957
|
},
|
|
28955
28958
|
async delFirebaseConfigJson(ctx) {
|
|
28956
28959
|
try {
|
|
28957
|
-
const isExist = await strapi.plugin("firebase-authentication").service("settingsService").delFirebaseConfigJson(
|
|
28960
|
+
const isExist = await strapi.plugin("firebase-authentication").service("settingsService").delFirebaseConfigJson();
|
|
28958
28961
|
if (!isExist) {
|
|
28959
28962
|
throw new NotFoundError("No Firebase configs exists for deletion");
|
|
28960
28963
|
}
|
|
@@ -29281,7 +29284,7 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29281
29284
|
try {
|
|
29282
29285
|
strapi2.log.info("Starting Firebase initialization...");
|
|
29283
29286
|
const res = await strapi2.db.query(CONFIG_CONTENT_TYPE).findOne({ where: {} });
|
|
29284
|
-
strapi2.log.debug(
|
|
29287
|
+
strapi2.log.debug(`Found config: ${!!res}`);
|
|
29285
29288
|
if (!res) {
|
|
29286
29289
|
strapi2.log.debug("No config found, checking for existing Firebase app...");
|
|
29287
29290
|
if (strapi2.firebase) {
|
|
@@ -29291,7 +29294,7 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29291
29294
|
return;
|
|
29292
29295
|
}
|
|
29293
29296
|
const jsonObject = res["firebase_config_json"];
|
|
29294
|
-
strapi2.log.debug(
|
|
29297
|
+
strapi2.log.debug(`Config JSON present: ${!!jsonObject?.firebaseConfigJson}`);
|
|
29295
29298
|
if (!jsonObject || !jsonObject.firebaseConfigJson) {
|
|
29296
29299
|
strapi2.log.debug("No valid JSON config, checking for existing Firebase app...");
|
|
29297
29300
|
if (strapi2.firebase) {
|
|
@@ -29326,11 +29329,11 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29326
29329
|
strapi2.firebase = admin__default.default;
|
|
29327
29330
|
strapi2.log.info("Firebase initialization complete - admin instance attached to strapi.firebase");
|
|
29328
29331
|
} catch (initError) {
|
|
29329
|
-
strapi2.log.error(
|
|
29332
|
+
strapi2.log.error(`Failed to initialize Firebase: ${initError.message}`);
|
|
29330
29333
|
throw initError;
|
|
29331
29334
|
}
|
|
29332
29335
|
} catch (error2) {
|
|
29333
|
-
strapi2.log.error(
|
|
29336
|
+
strapi2.log.error(`Firebase bootstrap error: ${error2.message}`);
|
|
29334
29337
|
}
|
|
29335
29338
|
},
|
|
29336
29339
|
/**
|
|
@@ -29378,7 +29381,7 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29378
29381
|
magicLinkExpiryHours: configObject.magicLinkExpiryHours || 1
|
|
29379
29382
|
};
|
|
29380
29383
|
} catch (error2) {
|
|
29381
|
-
strapi2.log.error(
|
|
29384
|
+
strapi2.log.error(`Firebase config error: ${error2.message}`);
|
|
29382
29385
|
throw new ApplicationError$1("Error retrieving Firebase config", {
|
|
29383
29386
|
error: error2.message
|
|
29384
29387
|
});
|
|
@@ -29405,10 +29408,9 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29405
29408
|
* The service account JSON is encrypted using AES before storage,
|
|
29406
29409
|
* while the Web API key and password settings are stored in plain text.
|
|
29407
29410
|
*/
|
|
29408
|
-
async setFirebaseConfigJson(
|
|
29411
|
+
async setFirebaseConfigJson(requestBody) {
|
|
29409
29412
|
try {
|
|
29410
|
-
strapi2.log.debug("setFirebaseConfigJson"
|
|
29411
|
-
const { body: requestBody } = ctx.request;
|
|
29413
|
+
strapi2.log.debug("setFirebaseConfigJson called");
|
|
29412
29414
|
const firebaseConfigJsonString = requestBody.firebaseConfigJson;
|
|
29413
29415
|
const firebaseWebApiKey = requestBody.firebaseWebApiKey || null;
|
|
29414
29416
|
const {
|
|
@@ -29479,18 +29481,17 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29479
29481
|
const configData = res.firebaseConfigJson || res.firebase_config_json;
|
|
29480
29482
|
if (!configData) {
|
|
29481
29483
|
strapi2.log.error("Firebase config data missing from database response");
|
|
29482
|
-
strapi2.log.error(
|
|
29484
|
+
strapi2.log.error(`Available keys in response: ${JSON.stringify(Object.keys(res))}`);
|
|
29483
29485
|
throw new ApplicationError2("Failed to retrieve Firebase configuration from database");
|
|
29484
29486
|
}
|
|
29485
29487
|
const firebaseConfigHash = configData.firebaseConfigJson;
|
|
29486
29488
|
if (!firebaseConfigHash) {
|
|
29487
|
-
strapi2.log.error(
|
|
29489
|
+
strapi2.log.error(`Firebase config hash missing from config data: ${JSON.stringify(configData)}`);
|
|
29488
29490
|
throw new ApplicationError2("Firebase configuration hash is missing");
|
|
29489
29491
|
}
|
|
29490
29492
|
const firebaseConfigJsonValue = await this.decryptJson(encryptionKey, firebaseConfigHash);
|
|
29491
|
-
|
|
29492
|
-
res.
|
|
29493
|
-
res.firebase_config_json = configData;
|
|
29493
|
+
res.firebaseConfigJson = firebaseConfigJsonValue;
|
|
29494
|
+
res.firebase_config_json = firebaseConfigJsonValue;
|
|
29494
29495
|
res.firebaseWebApiKey = res.firebase_web_api_key || null;
|
|
29495
29496
|
res.passwordRequirementsRegex = res.passwordRequirementsRegex || passwordRequirementsRegex;
|
|
29496
29497
|
res.passwordRequirementsMessage = res.passwordRequirementsMessage || passwordRequirementsMessage;
|
|
@@ -29503,13 +29504,12 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29503
29504
|
return res;
|
|
29504
29505
|
} catch (error2) {
|
|
29505
29506
|
strapi2.log.error("=== FIREBASE CONFIG SAVE ERROR ===");
|
|
29506
|
-
strapi2.log.error(
|
|
29507
|
-
strapi2.log.error(
|
|
29508
|
-
strapi2.log.error(
|
|
29507
|
+
strapi2.log.error(`Error name: ${error2.name}`);
|
|
29508
|
+
strapi2.log.error(`Error message: ${error2.message}`);
|
|
29509
|
+
strapi2.log.error(`Error stack: ${error2.stack}`);
|
|
29509
29510
|
try {
|
|
29510
|
-
|
|
29511
|
-
|
|
29512
|
-
strapi2.log.error("Request body keys:", Object.keys(body));
|
|
29511
|
+
if (requestBody) {
|
|
29512
|
+
strapi2.log.error(`Request body keys: ${JSON.stringify(Object.keys(requestBody))}`);
|
|
29513
29513
|
}
|
|
29514
29514
|
} catch (e) {
|
|
29515
29515
|
strapi2.log.error("Could not access request body");
|
|
@@ -29530,7 +29530,7 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29530
29530
|
try {
|
|
29531
29531
|
strapi2.log.debug("delFirebaseConfigJson called");
|
|
29532
29532
|
const isExist = await strapi2.db.query(CONFIG_CONTENT_TYPE).findOne({ where: {} });
|
|
29533
|
-
strapi2.log.debug(
|
|
29533
|
+
strapi2.log.debug(`Config exists: ${!!isExist}`);
|
|
29534
29534
|
if (!isExist) {
|
|
29535
29535
|
strapi2.log.info(ERROR_MESSAGES.DELETION_NO_CONFIG);
|
|
29536
29536
|
return null;
|
|
@@ -29538,12 +29538,12 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29538
29538
|
const res = await strapi2.db.query(CONFIG_CONTENT_TYPE).delete({
|
|
29539
29539
|
where: { id: isExist.id }
|
|
29540
29540
|
});
|
|
29541
|
-
strapi2.log.debug(
|
|
29541
|
+
strapi2.log.debug(`Delete result: ${JSON.stringify(res)}`);
|
|
29542
29542
|
await strapi2.plugin("firebase-authentication").service("settingsService").init();
|
|
29543
29543
|
strapi2.log.info(SUCCESS_MESSAGES.FIREBASE_CONFIG_DELETED);
|
|
29544
29544
|
return res;
|
|
29545
29545
|
} catch (error2) {
|
|
29546
|
-
strapi2.log.error(
|
|
29546
|
+
strapi2.log.error(`delFirebaseConfigJson error: ${error2.message}`);
|
|
29547
29547
|
throw new ApplicationError2(ERROR_MESSAGES.SOMETHING_WENT_WRONG, {
|
|
29548
29548
|
error: error2
|
|
29549
29549
|
});
|
|
@@ -29850,9 +29850,71 @@ const userService = ({ strapi: strapi2 }) => {
|
|
|
29850
29850
|
update: async (entityId, payload) => {
|
|
29851
29851
|
try {
|
|
29852
29852
|
ensureFirebaseInitialized();
|
|
29853
|
-
const
|
|
29854
|
-
|
|
29853
|
+
const firebaseData = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(entityId);
|
|
29854
|
+
if (!firebaseData?.user) {
|
|
29855
|
+
throw new NotFoundError(`User not found for Firebase UID: ${entityId}`);
|
|
29856
|
+
}
|
|
29857
|
+
const firebasePayload = {};
|
|
29858
|
+
if (payload.email !== void 0) firebasePayload.email = payload.email;
|
|
29859
|
+
if (payload.phoneNumber !== void 0) firebasePayload.phoneNumber = payload.phoneNumber;
|
|
29860
|
+
if (payload.displayName !== void 0) firebasePayload.displayName = payload.displayName;
|
|
29861
|
+
if (payload.photoURL !== void 0) firebasePayload.photoURL = payload.photoURL;
|
|
29862
|
+
if (payload.disabled !== void 0) firebasePayload.disabled = payload.disabled;
|
|
29863
|
+
if (payload.emailVerified !== void 0) firebasePayload.emailVerified = payload.emailVerified;
|
|
29864
|
+
if (payload.password !== void 0) firebasePayload.password = payload.password;
|
|
29865
|
+
const firebasePromise = strapi2.firebase.auth().updateUser(entityId, firebasePayload);
|
|
29866
|
+
const strapiPayload = {};
|
|
29867
|
+
if (payload.email !== void 0) {
|
|
29868
|
+
strapiPayload.email = payload.email;
|
|
29869
|
+
}
|
|
29870
|
+
if (payload.phoneNumber !== void 0) {
|
|
29871
|
+
strapiPayload.phoneNumber = payload.phoneNumber;
|
|
29872
|
+
}
|
|
29873
|
+
if (payload.displayName !== void 0) {
|
|
29874
|
+
if (payload.displayName) {
|
|
29875
|
+
const nameParts = payload.displayName.trim().split(" ");
|
|
29876
|
+
strapiPayload.firstName = nameParts[0] || "";
|
|
29877
|
+
strapiPayload.lastName = nameParts.slice(1).join(" ") || "";
|
|
29878
|
+
} else {
|
|
29879
|
+
strapiPayload.firstName = "";
|
|
29880
|
+
strapiPayload.lastName = "";
|
|
29881
|
+
}
|
|
29882
|
+
}
|
|
29883
|
+
if (typeof payload.disabled === "boolean") {
|
|
29884
|
+
strapiPayload.blocked = payload.disabled;
|
|
29885
|
+
}
|
|
29886
|
+
const strapiPromise = Object.keys(strapiPayload).length > 0 ? strapi2.db.query("plugin::users-permissions.user").update({
|
|
29887
|
+
where: { documentId: firebaseData.user.documentId },
|
|
29888
|
+
data: strapiPayload
|
|
29889
|
+
}) : Promise.resolve(firebaseData.user);
|
|
29890
|
+
const results = await Promise.allSettled([firebasePromise, strapiPromise]);
|
|
29891
|
+
strapi2.log.info("User update operation", {
|
|
29892
|
+
userId: entityId,
|
|
29893
|
+
firebaseStatus: results[0].status,
|
|
29894
|
+
strapiStatus: results[1].status,
|
|
29895
|
+
updatedFields: Object.keys(firebasePayload)
|
|
29896
|
+
});
|
|
29897
|
+
if (results[0].status === "rejected" || results[1].status === "rejected") {
|
|
29898
|
+
strapi2.log.error("Partial update failure detected", {
|
|
29899
|
+
userId: entityId,
|
|
29900
|
+
firebaseError: results[0].status === "rejected" ? results[0].reason : null,
|
|
29901
|
+
strapiError: results[1].status === "rejected" ? results[1].reason : null
|
|
29902
|
+
});
|
|
29903
|
+
}
|
|
29904
|
+
return results;
|
|
29855
29905
|
} catch (e) {
|
|
29906
|
+
if (e.code === "auth/email-already-exists") {
|
|
29907
|
+
throw new ValidationError$1("Email address is already in use by another account");
|
|
29908
|
+
}
|
|
29909
|
+
if (e.code === "auth/phone-number-already-exists") {
|
|
29910
|
+
throw new ValidationError$1("Phone number is already in use by another account");
|
|
29911
|
+
}
|
|
29912
|
+
if (e.code === "auth/invalid-email") {
|
|
29913
|
+
throw new ValidationError$1("Invalid email address format");
|
|
29914
|
+
}
|
|
29915
|
+
if (e.code === "auth/invalid-phone-number") {
|
|
29916
|
+
throw new ValidationError$1("Invalid phone number format");
|
|
29917
|
+
}
|
|
29856
29918
|
throw new ApplicationError$1(e.message.toString());
|
|
29857
29919
|
}
|
|
29858
29920
|
},
|
|
@@ -29870,8 +29932,8 @@ const userService = ({ strapi: strapi2 }) => {
|
|
|
29870
29932
|
if (!firebaseData?.user) {
|
|
29871
29933
|
throw new NotFoundError(`User not found for Firebase UID: ${entityId}`);
|
|
29872
29934
|
}
|
|
29873
|
-
return await strapi2.
|
|
29874
|
-
documentId: firebaseData.user.documentId,
|
|
29935
|
+
return await strapi2.db.query("plugin::users-permissions.user").update({
|
|
29936
|
+
where: { documentId: firebaseData.user.documentId },
|
|
29875
29937
|
data: payload
|
|
29876
29938
|
});
|
|
29877
29939
|
} catch (e) {
|
|
@@ -29886,8 +29948,8 @@ const userService = ({ strapi: strapi2 }) => {
|
|
|
29886
29948
|
throw new NotFoundError(`User not found for Firebase UID: ${entityId}`);
|
|
29887
29949
|
}
|
|
29888
29950
|
const firebasePromise = strapi2.firebase.auth().updateUser(entityId, payload);
|
|
29889
|
-
const strapiPromise = strapi2.
|
|
29890
|
-
documentId: firebaseData.user.documentId,
|
|
29951
|
+
const strapiPromise = strapi2.db.query("plugin::users-permissions.user").update({
|
|
29952
|
+
where: { documentId: firebaseData.user.documentId },
|
|
29891
29953
|
data: payload
|
|
29892
29954
|
});
|
|
29893
29955
|
return Promise.allSettled([firebasePromise, strapiPromise]);
|
|
@@ -29903,8 +29965,8 @@ const userService = ({ strapi: strapi2 }) => {
|
|
|
29903
29965
|
throw new NotFoundError(`User not found for Firebase UID: ${entityId}`);
|
|
29904
29966
|
}
|
|
29905
29967
|
const firebasePromise = strapi2.firebase.auth().deleteUser(entityId);
|
|
29906
|
-
const strapiPromise = strapi2.
|
|
29907
|
-
documentId: firebaseData.user.documentId
|
|
29968
|
+
const strapiPromise = strapi2.db.query("plugin::users-permissions.user").delete({
|
|
29969
|
+
where: { documentId: firebaseData.user.documentId }
|
|
29908
29970
|
});
|
|
29909
29971
|
return Promise.allSettled([firebasePromise, strapiPromise]);
|
|
29910
29972
|
} catch (e) {
|
|
@@ -29926,8 +29988,8 @@ const userService = ({ strapi: strapi2 }) => {
|
|
|
29926
29988
|
if (!firebaseData?.user) {
|
|
29927
29989
|
throw new NotFoundError(`User not found for Firebase UID: ${entityId}`);
|
|
29928
29990
|
}
|
|
29929
|
-
const response = await strapi2.
|
|
29930
|
-
documentId: firebaseData.user.documentId
|
|
29991
|
+
const response = await strapi2.db.query("plugin::users-permissions.user").delete({
|
|
29992
|
+
where: { documentId: firebaseData.user.documentId }
|
|
29931
29993
|
});
|
|
29932
29994
|
return response;
|
|
29933
29995
|
} catch (e) {
|
|
@@ -30466,8 +30528,8 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30466
30528
|
* Forgot password flow - sends reset email
|
|
30467
30529
|
* Public endpoint that sends a Firebase-hosted password reset email using Firebase's secure hosted UI
|
|
30468
30530
|
*/
|
|
30469
|
-
forgotPassword: async (
|
|
30470
|
-
|
|
30531
|
+
forgotPassword: async (email2) => {
|
|
30532
|
+
strapi2.log.info(`[forgotPassword] Starting password reset for email: ${email2}`);
|
|
30471
30533
|
if (!email2) {
|
|
30472
30534
|
throw new ValidationError$1("Email is required");
|
|
30473
30535
|
}
|
|
@@ -30508,8 +30570,16 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30508
30570
|
});
|
|
30509
30571
|
}
|
|
30510
30572
|
if (!strapiUser) {
|
|
30573
|
+
strapi2.log.warn(`⚠️ [forgotPassword] User not found for email: ${email2}`);
|
|
30511
30574
|
return { message: "If an account with that email exists, a password reset link has been sent." };
|
|
30512
30575
|
}
|
|
30576
|
+
strapi2.log.info(
|
|
30577
|
+
`✅ [forgotPassword] User found: ${JSON.stringify({
|
|
30578
|
+
documentId: strapiUser.documentId,
|
|
30579
|
+
email: strapiUser.email,
|
|
30580
|
+
firebaseUID: firebaseUser?.uid || "not in Firebase"
|
|
30581
|
+
})}`
|
|
30582
|
+
);
|
|
30513
30583
|
const actionCodeSettings = {
|
|
30514
30584
|
url: resetUrl,
|
|
30515
30585
|
// Continue URL after reset completes on Firebase's page
|
|
@@ -30523,6 +30593,7 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30523
30593
|
});
|
|
30524
30594
|
let resetLink;
|
|
30525
30595
|
try {
|
|
30596
|
+
strapi2.log.info(`[forgotPassword] Generating Firebase password reset link for: ${strapiUser.email}`);
|
|
30526
30597
|
resetLink = await Promise.race([
|
|
30527
30598
|
strapi2.firebase.auth().generatePasswordResetLink(strapiUser.email, actionCodeSettings),
|
|
30528
30599
|
timeoutPromise
|
|
@@ -30534,12 +30605,22 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30534
30605
|
strapi2.log.error(`❌ Failed to generate password reset link for ${strapiUser.email}:`, error2);
|
|
30535
30606
|
throw error2;
|
|
30536
30607
|
}
|
|
30608
|
+
strapi2.log.info(`[forgotPassword] Attempting to send password reset email to: ${strapiUser.email}`);
|
|
30537
30609
|
await strapi2.plugin("firebase-authentication").service("emailService").sendPasswordResetEmail(strapiUser, resetLink);
|
|
30610
|
+
strapi2.log.info(`✅ [forgotPassword] Password reset email sent successfully to: ${strapiUser.email}`);
|
|
30538
30611
|
return {
|
|
30539
30612
|
message: "If an account with that email exists, a password reset link has been sent."
|
|
30540
30613
|
};
|
|
30541
30614
|
} catch (error2) {
|
|
30542
|
-
strapi2.log.error(
|
|
30615
|
+
strapi2.log.error(
|
|
30616
|
+
`❌ [forgotPassword] ERROR: ${JSON.stringify({
|
|
30617
|
+
email: email2,
|
|
30618
|
+
message: error2.message,
|
|
30619
|
+
code: error2.code,
|
|
30620
|
+
name: error2.name,
|
|
30621
|
+
stack: error2.stack
|
|
30622
|
+
})}`
|
|
30623
|
+
);
|
|
30543
30624
|
return {
|
|
30544
30625
|
message: "If an account with that email exists, a password reset link has been sent."
|
|
30545
30626
|
};
|
|
@@ -30559,13 +30640,10 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30559
30640
|
*
|
|
30560
30641
|
* NOT used for forgot password email flow - that now uses Firebase's hosted UI
|
|
30561
30642
|
*/
|
|
30562
|
-
resetPassword: async (
|
|
30563
|
-
const { password } = ctx.request.body;
|
|
30564
|
-
const populate2 = ctx.request.query.populate || [];
|
|
30643
|
+
resetPassword: async (password, token, populate2) => {
|
|
30565
30644
|
if (!password) {
|
|
30566
30645
|
throw new ValidationError$1("Password is required");
|
|
30567
30646
|
}
|
|
30568
|
-
const token = ctx.request.header.authorization?.replace("Bearer ", "");
|
|
30569
30647
|
if (!token) {
|
|
30570
30648
|
throw new UnauthorizedError("Authorization token is required");
|
|
30571
30649
|
}
|
|
@@ -30621,8 +30699,7 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30621
30699
|
* Generates a sign-in link using Firebase Admin SDK
|
|
30622
30700
|
* Note: Verification requires client-side completion
|
|
30623
30701
|
*/
|
|
30624
|
-
async requestMagicLink(
|
|
30625
|
-
const { email: email2 } = ctx.request.body;
|
|
30702
|
+
async requestMagicLink(email2) {
|
|
30626
30703
|
if (!email2 || typeof email2 !== "string") {
|
|
30627
30704
|
throw new ValidationError$1("Valid email is required");
|
|
30628
30705
|
}
|
|
@@ -30652,7 +30729,7 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30652
30729
|
};
|
|
30653
30730
|
const magicLink = await strapi2.firebase.auth().generateSignInWithEmailLink(email2, actionCodeSettings);
|
|
30654
30731
|
if (process.env.NODE_ENV !== "production") {
|
|
30655
|
-
strapi2.log.info("
|
|
30732
|
+
strapi2.log.info("Magic Link Generation Request:");
|
|
30656
30733
|
strapi2.log.info(` Email: ${email2}`);
|
|
30657
30734
|
strapi2.log.info(` Verification URL: ${magicLinkUrl}`);
|
|
30658
30735
|
strapi2.log.info(` Expires: ${config2.magicLinkExpiryHours || 1} hour(s)`);
|
|
@@ -31258,7 +31335,7 @@ class EmailService {
|
|
|
31258
31335
|
const template = await templateService2.getTemplate("magicLink");
|
|
31259
31336
|
const compiledSubject = _$1.template(template.subject)(completeVariables);
|
|
31260
31337
|
strapi.log.info("\n" + "=".repeat(80));
|
|
31261
|
-
strapi.log.info("
|
|
31338
|
+
strapi.log.info("MAGIC LINK EMAIL (Development Mode)");
|
|
31262
31339
|
strapi.log.info("=".repeat(80));
|
|
31263
31340
|
strapi.log.info(`To: ${email2}`);
|
|
31264
31341
|
strapi.log.info(`Subject: ${compiledSubject}`);
|
|
@@ -31333,7 +31410,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
|
|
|
31333
31410
|
}
|
|
31334
31411
|
});
|
|
31335
31412
|
} catch (error2) {
|
|
31336
|
-
if (error2.code === "23505") {
|
|
31413
|
+
if (error2.code === "23505" || error2.name === "ValidationError") {
|
|
31337
31414
|
strapi2.log.warn(`Race condition detected for user ${userId}, retrying findFirst`);
|
|
31338
31415
|
firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
|
|
31339
31416
|
filters: { user: { documentId: { $eq: userId } } }
|
|
@@ -31373,7 +31450,7 @@ const autoLinkService = {
|
|
|
31373
31450
|
errors: 0
|
|
31374
31451
|
};
|
|
31375
31452
|
try {
|
|
31376
|
-
strapi2.log.info("
|
|
31453
|
+
strapi2.log.info("Auto-linking Strapi users with Firebase users...");
|
|
31377
31454
|
if (!strapi2.firebase) {
|
|
31378
31455
|
strapi2.log.warn("Firebase not initialized - skipping auto-linking");
|
|
31379
31456
|
return result;
|
|
@@ -31412,6 +31489,7 @@ const autoLinkService = {
|
|
|
31412
31489
|
}
|
|
31413
31490
|
}
|
|
31414
31491
|
for (const strapiUser of strapiUsers) {
|
|
31492
|
+
let firebaseUser = null;
|
|
31415
31493
|
try {
|
|
31416
31494
|
const existing = await strapi2.db.query("plugin::firebase-authentication.firebase-user-data").findOne({
|
|
31417
31495
|
select: ["id"],
|
|
@@ -31421,7 +31499,7 @@ const autoLinkService = {
|
|
|
31421
31499
|
result.skipped++;
|
|
31422
31500
|
continue;
|
|
31423
31501
|
}
|
|
31424
|
-
|
|
31502
|
+
firebaseUser = null;
|
|
31425
31503
|
if (strapiUser.email) {
|
|
31426
31504
|
firebaseUser = firebaseByEmail.get(strapiUser.email.toLowerCase());
|
|
31427
31505
|
}
|
|
@@ -31432,6 +31510,23 @@ const autoLinkService = {
|
|
|
31432
31510
|
result.skipped++;
|
|
31433
31511
|
continue;
|
|
31434
31512
|
}
|
|
31513
|
+
const existingUIDLink = await strapi2.db.query("plugin::firebase-authentication.firebase-user-data").findOne({
|
|
31514
|
+
where: { firebaseUserID: firebaseUser.uid },
|
|
31515
|
+
populate: ["user"]
|
|
31516
|
+
});
|
|
31517
|
+
if (existingUIDLink && existingUIDLink.user?.documentId !== strapiUser.documentId) {
|
|
31518
|
+
strapi2.log.warn(
|
|
31519
|
+
`⚠️ [Auto-Link] Skipping '${strapiUser.username || strapiUser.email}' - Firebase UID already linked`
|
|
31520
|
+
);
|
|
31521
|
+
strapi2.log.warn(` Strapi User: ${strapiUser.email} (documentId: ${strapiUser.documentId})`);
|
|
31522
|
+
strapi2.log.warn(` Firebase UID: ${firebaseUser.uid}`);
|
|
31523
|
+
strapi2.log.warn(
|
|
31524
|
+
` Already linked to: ${existingUIDLink.user?.email} (documentId: ${existingUIDLink.user?.documentId})`
|
|
31525
|
+
);
|
|
31526
|
+
strapi2.log.warn(` Action: Resolve duplicate users or manually unlink conflicting record`);
|
|
31527
|
+
result.skipped++;
|
|
31528
|
+
continue;
|
|
31529
|
+
}
|
|
31435
31530
|
try {
|
|
31436
31531
|
const firebaseData = {
|
|
31437
31532
|
firebaseUserID: firebaseUser.uid
|
|
@@ -31450,18 +31545,42 @@ const autoLinkService = {
|
|
|
31450
31545
|
throw createError;
|
|
31451
31546
|
}
|
|
31452
31547
|
} catch (error2) {
|
|
31453
|
-
|
|
31454
|
-
|
|
31548
|
+
if (error2.message?.includes("This attribute must be unique")) {
|
|
31549
|
+
strapi2.log.warn(
|
|
31550
|
+
`⚠️ [Auto-Link] Unique constraint conflict for '${strapiUser.username || strapiUser.email}'`
|
|
31551
|
+
);
|
|
31552
|
+
strapi2.log.warn(` Strapi User: ${strapiUser.email} (documentId: ${strapiUser.documentId})`);
|
|
31553
|
+
if (firebaseUser) {
|
|
31554
|
+
strapi2.log.warn(` Firebase UID: ${firebaseUser.uid}`);
|
|
31555
|
+
strapi2.log.warn(` Cause: This Firebase UID is already linked to another Strapi user`);
|
|
31556
|
+
strapi2.log.warn(
|
|
31557
|
+
` Action: Query firebase_user_data table to find conflict - WHERE firebase_user_id = '${firebaseUser.uid}'`
|
|
31558
|
+
);
|
|
31559
|
+
}
|
|
31560
|
+
result.skipped++;
|
|
31561
|
+
} else {
|
|
31562
|
+
result.errors++;
|
|
31563
|
+
strapi2.log.error(
|
|
31564
|
+
`❌ [Auto-Link] Unexpected error linking user '${strapiUser.username || strapiUser.email}': ${error2.message}`
|
|
31565
|
+
);
|
|
31566
|
+
}
|
|
31455
31567
|
}
|
|
31456
31568
|
}
|
|
31457
|
-
|
|
31458
|
-
|
|
31459
|
-
|
|
31569
|
+
if (result.errors > 0) {
|
|
31570
|
+
strapi2.log.error(
|
|
31571
|
+
`❌ Auto-linking completed with unexpected errors: ${result.linked} linked, ${result.skipped} skipped, ${result.errors} errors`
|
|
31572
|
+
);
|
|
31573
|
+
strapi2.log.error(` Review error logs above for resolution steps`);
|
|
31574
|
+
} else {
|
|
31575
|
+
strapi2.log.info(
|
|
31576
|
+
`✅ Auto-linking complete: ${result.linked} linked, ${result.skipped} skipped, ${result.errors} errors`
|
|
31577
|
+
);
|
|
31578
|
+
}
|
|
31460
31579
|
strapi2.log.info(
|
|
31461
31580
|
` Total: ${result.totalStrapiUsers} Strapi users, ${result.totalFirebaseUsers} Firebase users`
|
|
31462
31581
|
);
|
|
31463
31582
|
} catch (error2) {
|
|
31464
|
-
strapi2.log.error(
|
|
31583
|
+
strapi2.log.error(`❌ Fatal error during auto-linking: ${error2.message}`);
|
|
31465
31584
|
}
|
|
31466
31585
|
return result;
|
|
31467
31586
|
}
|