strapi-plugin-firebase-authentication 1.1.0 → 1.1.8
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/README.md +51 -17
- package/dist/_chunks/{App-HfsY_18f.js → App-C_pWLYYH.js} +170 -101
- package/dist/_chunks/{App-Bl6D4TFu.mjs → App-Dt8F60Rl.mjs} +39 -8
- package/dist/_chunks/{api-BSejy8nn.js → api-CxfueBVM.js} +1 -1
- package/dist/_chunks/{api-B01IAVEC.mjs → api-T8QRCile.mjs} +1 -1
- package/dist/_chunks/{index-DgfRCyyQ.js → index-BIHS9XB4.js} +2 -2
- package/dist/_chunks/{index-BqF9RRVF.mjs → index-BzSU0Li9.mjs} +1 -1
- package/dist/_chunks/{index-BbVqBI3M.js → index-C87l6qcA.js} +1 -1
- package/dist/_chunks/{index-4hUrKd7Y.mjs → index-Do9Y0scX.mjs} +2 -2
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +153 -145
- package/dist/server/index.mjs +153 -145
- package/dist/server/src/controllers/firebaseController.d.ts +4 -2
- package/dist/server/src/controllers/index.d.ts +0 -1
- package/dist/server/src/controllers/settingsController.d.ts +0 -1
- package/dist/server/src/index.d.ts +3 -11
- package/dist/server/src/routes/index.d.ts +0 -10
- package/dist/server/src/services/firebaseService.d.ts +12 -2
- package/package.json +11 -10
- package/dist/server/src/routes/content-internal-api.d.ts +0 -11
|
@@ -4,7 +4,7 @@ const jsxRuntime = require("react/jsx-runtime");
|
|
|
4
4
|
const React = require("react");
|
|
5
5
|
const designSystem = require("@strapi/design-system");
|
|
6
6
|
const admin = require("@strapi/strapi/admin");
|
|
7
|
-
const api = require("./api-
|
|
7
|
+
const api = require("./api-CxfueBVM.js");
|
|
8
8
|
const reactRouterDom = require("react-router-dom");
|
|
9
9
|
function SettingsPage() {
|
|
10
10
|
const { toggleNotification } = admin.useNotification();
|
|
@@ -738,7 +738,7 @@ const index = {
|
|
|
738
738
|
id: `${PLUGIN_ID}.page.title`,
|
|
739
739
|
defaultMessage: PLUGIN_ID
|
|
740
740
|
},
|
|
741
|
-
Component: () => import("./App-
|
|
741
|
+
Component: () => import("./App-Dt8F60Rl.mjs").then((mod) => ({
|
|
742
742
|
default: mod.App
|
|
743
743
|
})),
|
|
744
744
|
permissions: PERMISSIONS["menu-link"]
|
|
@@ -760,7 +760,7 @@ const index = {
|
|
|
760
760
|
id: "settings",
|
|
761
761
|
to: `/settings/${PLUGIN_ID}`,
|
|
762
762
|
async Component() {
|
|
763
|
-
const component = await import("./index-
|
|
763
|
+
const component = await import("./index-BzSU0Li9.mjs");
|
|
764
764
|
return component.default;
|
|
765
765
|
},
|
|
766
766
|
permissions: PERMISSIONS["menu-link"]
|
package/dist/admin/index.js
CHANGED
package/dist/admin/index.mjs
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -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("validateToken controller error:", error2);
|
|
445
|
+
strapi.log.error("validateToken controller error:", error2.message);
|
|
446
446
|
if (error2.name === "ValidationError") {
|
|
447
447
|
return ctx.badRequest(error2.message);
|
|
448
448
|
}
|
|
@@ -532,9 +532,11 @@ const firebaseController = {
|
|
|
532
532
|
}
|
|
533
533
|
},
|
|
534
534
|
/**
|
|
535
|
-
* Reset password - authenticated
|
|
535
|
+
* Reset password - authenticated password change
|
|
536
536
|
* POST /api/firebase-authentication/resetPassword
|
|
537
|
-
* Public endpoint -
|
|
537
|
+
* Public endpoint - requires valid JWT in Authorization header
|
|
538
|
+
* Used for admin-initiated resets or user self-service password changes
|
|
539
|
+
* NOT used for forgot password email flow (which uses Firebase's hosted UI)
|
|
538
540
|
*/
|
|
539
541
|
async resetPassword(ctx) {
|
|
540
542
|
strapi.log.debug("resetPassword endpoint called");
|
|
@@ -5218,13 +5220,13 @@ lodash.exports;
|
|
|
5218
5220
|
return string2.slice(position, position + target.length) == target;
|
|
5219
5221
|
}
|
|
5220
5222
|
function template(string2, options2, guard) {
|
|
5221
|
-
var
|
|
5223
|
+
var settings = lodash2.templateSettings;
|
|
5222
5224
|
if (guard && isIterateeCall(string2, options2, guard)) {
|
|
5223
5225
|
options2 = undefined$1;
|
|
5224
5226
|
}
|
|
5225
5227
|
string2 = toString4(string2);
|
|
5226
|
-
options2 = assignInWith({}, options2,
|
|
5227
|
-
var imports = assignInWith({}, options2.imports,
|
|
5228
|
+
options2 = assignInWith({}, options2, settings, customDefaultsAssignIn);
|
|
5229
|
+
var imports = assignInWith({}, options2.imports, settings.imports, customDefaultsAssignIn), importsKeys = keys2(imports), importsValues = baseValues(imports, importsKeys);
|
|
5228
5230
|
var isEscaping, isEvaluating, index2 = 0, interpolate = options2.interpolate || reNoMatch, source = "__p += '";
|
|
5229
5231
|
var reDelimiters = RegExp2(
|
|
5230
5232
|
(options2.escape || reNoMatch).source + "|" + interpolate.source + "|" + (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + "|" + (options2.evaluate || reNoMatch).source + "|$",
|
|
@@ -28934,9 +28936,6 @@ const userController = {
|
|
|
28934
28936
|
}
|
|
28935
28937
|
};
|
|
28936
28938
|
const settingsController = {
|
|
28937
|
-
setToken: async (ctx) => {
|
|
28938
|
-
ctx.body = await strapi.plugin("firebase-authentication").service("settingsService").setToken(ctx);
|
|
28939
|
-
},
|
|
28940
28939
|
setFirebaseConfigJson: async (ctx) => {
|
|
28941
28940
|
ctx.body = await strapi.plugin("firebase-authentication").service("settingsService").setFirebaseConfigJson(ctx);
|
|
28942
28941
|
},
|
|
@@ -29091,13 +29090,7 @@ const controllers = {
|
|
|
29091
29090
|
};
|
|
29092
29091
|
const middlewares = {};
|
|
29093
29092
|
const policies = {};
|
|
29094
|
-
const
|
|
29095
|
-
{
|
|
29096
|
-
method: "POST",
|
|
29097
|
-
path: "/settings/token",
|
|
29098
|
-
handler: "settingsController.setToken",
|
|
29099
|
-
config: { policies: ["admin::isAuthenticatedAdmin"] }
|
|
29100
|
-
},
|
|
29093
|
+
const settingsRoute = [
|
|
29101
29094
|
{
|
|
29102
29095
|
method: "POST",
|
|
29103
29096
|
path: "/settings/firebase-config",
|
|
@@ -29131,75 +29124,9 @@ const settings = [
|
|
|
29131
29124
|
];
|
|
29132
29125
|
const admin = {
|
|
29133
29126
|
type: "admin",
|
|
29134
|
-
routes: [...settings]
|
|
29135
|
-
};
|
|
29136
|
-
const contentApi = {
|
|
29137
|
-
type: "content-api",
|
|
29138
|
-
routes: [
|
|
29139
|
-
{
|
|
29140
|
-
method: "POST",
|
|
29141
|
-
path: "/",
|
|
29142
|
-
handler: "firebaseController.validateToken",
|
|
29143
|
-
config: {
|
|
29144
|
-
auth: false,
|
|
29145
|
-
// Public endpoint - this IS the authentication endpoint
|
|
29146
|
-
policies: []
|
|
29147
|
-
}
|
|
29148
|
-
},
|
|
29149
|
-
{
|
|
29150
|
-
method: "POST",
|
|
29151
|
-
path: "/emailLogin",
|
|
29152
|
-
handler: "firebaseController.emailLogin",
|
|
29153
|
-
config: {
|
|
29154
|
-
auth: false,
|
|
29155
|
-
// Public endpoint - email/password login
|
|
29156
|
-
policies: []
|
|
29157
|
-
}
|
|
29158
|
-
},
|
|
29159
|
-
{
|
|
29160
|
-
method: "POST",
|
|
29161
|
-
path: "/forgotPassword",
|
|
29162
|
-
handler: "firebaseController.forgotPassword",
|
|
29163
|
-
config: {
|
|
29164
|
-
auth: false,
|
|
29165
|
-
// Public endpoint - no authentication required
|
|
29166
|
-
policies: []
|
|
29167
|
-
}
|
|
29168
|
-
},
|
|
29169
|
-
{
|
|
29170
|
-
method: "POST",
|
|
29171
|
-
path: "/resetPassword",
|
|
29172
|
-
handler: "firebaseController.resetPassword",
|
|
29173
|
-
config: {
|
|
29174
|
-
auth: false,
|
|
29175
|
-
// Public endpoint - uses JWT from Authorization header
|
|
29176
|
-
policies: []
|
|
29177
|
-
}
|
|
29178
|
-
},
|
|
29179
|
-
{
|
|
29180
|
-
method: "GET",
|
|
29181
|
-
path: "/config",
|
|
29182
|
-
handler: "settingsController.getPublicConfig",
|
|
29183
|
-
config: {
|
|
29184
|
-
auth: false,
|
|
29185
|
-
// Public endpoint - frontend needs this for validation
|
|
29186
|
-
policies: []
|
|
29187
|
-
}
|
|
29188
|
-
},
|
|
29189
|
-
{
|
|
29190
|
-
method: "POST",
|
|
29191
|
-
path: "/requestMagicLink",
|
|
29192
|
-
handler: "firebaseController.requestMagicLink",
|
|
29193
|
-
config: {
|
|
29194
|
-
auth: false,
|
|
29195
|
-
// Public endpoint - passwordless authentication
|
|
29196
|
-
policies: []
|
|
29197
|
-
}
|
|
29198
|
-
}
|
|
29199
|
-
]
|
|
29200
|
-
};
|
|
29201
|
-
const contentInternalApi = {
|
|
29202
29127
|
routes: [
|
|
29128
|
+
...settingsRoute,
|
|
29129
|
+
// User management routes
|
|
29203
29130
|
{
|
|
29204
29131
|
method: "GET",
|
|
29205
29132
|
path: "/users",
|
|
@@ -29263,23 +29190,77 @@ const contentInternalApi = {
|
|
|
29263
29190
|
config: {
|
|
29264
29191
|
policies: ["admin::isAuthenticatedAdmin"]
|
|
29265
29192
|
}
|
|
29193
|
+
}
|
|
29194
|
+
]
|
|
29195
|
+
};
|
|
29196
|
+
const contentApi = {
|
|
29197
|
+
type: "content-api",
|
|
29198
|
+
routes: [
|
|
29199
|
+
{
|
|
29200
|
+
method: "POST",
|
|
29201
|
+
path: "/",
|
|
29202
|
+
handler: "firebaseController.validateToken",
|
|
29203
|
+
config: {
|
|
29204
|
+
auth: false,
|
|
29205
|
+
// Public endpoint - this IS the authentication endpoint
|
|
29206
|
+
policies: []
|
|
29207
|
+
}
|
|
29208
|
+
},
|
|
29209
|
+
{
|
|
29210
|
+
method: "POST",
|
|
29211
|
+
path: "/emailLogin",
|
|
29212
|
+
handler: "firebaseController.emailLogin",
|
|
29213
|
+
config: {
|
|
29214
|
+
auth: false,
|
|
29215
|
+
// Public endpoint - email/password login
|
|
29216
|
+
policies: []
|
|
29217
|
+
}
|
|
29218
|
+
},
|
|
29219
|
+
{
|
|
29220
|
+
method: "POST",
|
|
29221
|
+
path: "/forgotPassword",
|
|
29222
|
+
handler: "firebaseController.forgotPassword",
|
|
29223
|
+
config: {
|
|
29224
|
+
auth: false,
|
|
29225
|
+
// Public endpoint - no authentication required
|
|
29226
|
+
policies: []
|
|
29227
|
+
}
|
|
29228
|
+
},
|
|
29229
|
+
{
|
|
29230
|
+
method: "POST",
|
|
29231
|
+
path: "/resetPassword",
|
|
29232
|
+
handler: "firebaseController.resetPassword",
|
|
29233
|
+
config: {
|
|
29234
|
+
auth: false,
|
|
29235
|
+
// Public endpoint - authenticated password change, requires valid JWT in Authorization header
|
|
29236
|
+
policies: []
|
|
29237
|
+
}
|
|
29266
29238
|
},
|
|
29267
29239
|
{
|
|
29268
29240
|
method: "GET",
|
|
29269
29241
|
path: "/config",
|
|
29270
29242
|
handler: "settingsController.getPublicConfig",
|
|
29271
29243
|
config: {
|
|
29244
|
+
auth: false,
|
|
29245
|
+
// Public endpoint - frontend needs this for validation
|
|
29272
29246
|
policies: []
|
|
29273
|
-
// This is intentionally public for frontend config
|
|
29274
29247
|
}
|
|
29275
29248
|
},
|
|
29276
|
-
|
|
29249
|
+
{
|
|
29250
|
+
method: "POST",
|
|
29251
|
+
path: "/requestMagicLink",
|
|
29252
|
+
handler: "firebaseController.requestMagicLink",
|
|
29253
|
+
config: {
|
|
29254
|
+
auth: false,
|
|
29255
|
+
// Public endpoint - passwordless authentication
|
|
29256
|
+
policies: []
|
|
29257
|
+
}
|
|
29258
|
+
}
|
|
29277
29259
|
]
|
|
29278
29260
|
};
|
|
29279
29261
|
const routes = {
|
|
29280
29262
|
admin,
|
|
29281
|
-
"content-api": contentApi
|
|
29282
|
-
"content-internal-api": contentInternalApi
|
|
29263
|
+
"content-api": contentApi
|
|
29283
29264
|
};
|
|
29284
29265
|
const checkValidJson = (jsonString) => {
|
|
29285
29266
|
try {
|
|
@@ -29571,7 +29552,7 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29571
29552
|
/**
|
|
29572
29553
|
* Updates only the magic link settings without affecting other configuration
|
|
29573
29554
|
*/
|
|
29574
|
-
async updateMagicLinkSettings(
|
|
29555
|
+
async updateMagicLinkSettings(settings) {
|
|
29575
29556
|
try {
|
|
29576
29557
|
const foundConfig = await strapi2.db.query(CONFIG_CONTENT_TYPE).findOne({ where: {} });
|
|
29577
29558
|
if (!foundConfig) {
|
|
@@ -29580,10 +29561,10 @@ const settingsService = ({ strapi: strapi2 }) => {
|
|
|
29580
29561
|
const result = await strapi2.db.query(CONFIG_CONTENT_TYPE).update({
|
|
29581
29562
|
where: { id: foundConfig.id },
|
|
29582
29563
|
data: {
|
|
29583
|
-
enableMagicLink:
|
|
29584
|
-
magicLinkUrl:
|
|
29585
|
-
magicLinkEmailSubject:
|
|
29586
|
-
magicLinkExpiryHours:
|
|
29564
|
+
enableMagicLink: settings.enableMagicLink,
|
|
29565
|
+
magicLinkUrl: settings.magicLinkUrl,
|
|
29566
|
+
magicLinkEmailSubject: settings.magicLinkEmailSubject,
|
|
29567
|
+
magicLinkExpiryHours: settings.magicLinkExpiryHours
|
|
29587
29568
|
}
|
|
29588
29569
|
});
|
|
29589
29570
|
return {
|
|
@@ -29999,7 +29980,7 @@ const userService = ({ strapi: strapi2 }) => {
|
|
|
29999
29980
|
try {
|
|
30000
29981
|
const actionCodeSettings = {
|
|
30001
29982
|
url: passwordResetUrl,
|
|
30002
|
-
handleCodeInApp:
|
|
29983
|
+
handleCodeInApp: false
|
|
30003
29984
|
};
|
|
30004
29985
|
const timeoutPromise = new Promise((_2, reject) => {
|
|
30005
29986
|
setTimeout(
|
|
@@ -30220,17 +30201,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30220
30201
|
});
|
|
30221
30202
|
if (userByEmail) {
|
|
30222
30203
|
validateUserNotBlocked(userByEmail);
|
|
30223
|
-
|
|
30224
|
-
|
|
30225
|
-
|
|
30226
|
-
|
|
30227
|
-
strapi2.log.info(`Auto-linked user ${userByEmail.username} to Firebase UID ${firebaseUID}`);
|
|
30228
|
-
} catch (error2) {
|
|
30229
|
-
if (error2.code !== "23505") {
|
|
30230
|
-
throw error2;
|
|
30231
|
-
}
|
|
30232
|
-
strapi2.log.info(`User ${userByEmail.username} already linked to Firebase (race condition handled)`);
|
|
30204
|
+
const existingLink = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(firebaseUID);
|
|
30205
|
+
if (existingLink && existingLink.user) {
|
|
30206
|
+
validateUserNotBlocked(existingLink.user);
|
|
30207
|
+
return existingLink.user;
|
|
30233
30208
|
}
|
|
30209
|
+
await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByEmail.documentId, { firebaseUserID: firebaseUID });
|
|
30210
|
+
strapi2.log.info(`Auto-linked user ${userByEmail.username} to Firebase UID ${firebaseUID}`);
|
|
30234
30211
|
return userByEmail;
|
|
30235
30212
|
}
|
|
30236
30213
|
const firebaseDataByApple = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findMany({
|
|
@@ -30244,21 +30221,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30244
30221
|
const userByAppleEmail = firebaseDataByApple?.[0]?.user || null;
|
|
30245
30222
|
if (userByAppleEmail) {
|
|
30246
30223
|
validateUserNotBlocked(userByAppleEmail);
|
|
30247
|
-
|
|
30248
|
-
|
|
30249
|
-
|
|
30250
|
-
|
|
30251
|
-
strapi2.log.info(
|
|
30252
|
-
`Auto-linked Apple user ${userByAppleEmail.username} to Firebase UID ${firebaseUID}`
|
|
30253
|
-
);
|
|
30254
|
-
} catch (error2) {
|
|
30255
|
-
if (error2.code !== "23505") {
|
|
30256
|
-
throw error2;
|
|
30257
|
-
}
|
|
30258
|
-
strapi2.log.info(
|
|
30259
|
-
`User ${userByAppleEmail.username} already linked to Firebase (race condition handled)`
|
|
30260
|
-
);
|
|
30224
|
+
const existingLink = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(firebaseUID);
|
|
30225
|
+
if (existingLink && existingLink.user) {
|
|
30226
|
+
validateUserNotBlocked(existingLink.user);
|
|
30227
|
+
return existingLink.user;
|
|
30261
30228
|
}
|
|
30229
|
+
await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByAppleEmail.documentId, { firebaseUserID: firebaseUID });
|
|
30230
|
+
strapi2.log.info(`Auto-linked Apple user ${userByAppleEmail.username} to Firebase UID ${firebaseUID}`);
|
|
30262
30231
|
return userByAppleEmail;
|
|
30263
30232
|
}
|
|
30264
30233
|
}
|
|
@@ -30269,17 +30238,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30269
30238
|
});
|
|
30270
30239
|
if (userByPhone) {
|
|
30271
30240
|
validateUserNotBlocked(userByPhone);
|
|
30272
|
-
|
|
30273
|
-
|
|
30274
|
-
|
|
30275
|
-
|
|
30276
|
-
strapi2.log.info(`Auto-linked phone user ${userByPhone.username} to Firebase UID ${firebaseUID}`);
|
|
30277
|
-
} catch (error2) {
|
|
30278
|
-
if (error2.code !== "23505") {
|
|
30279
|
-
throw error2;
|
|
30280
|
-
}
|
|
30281
|
-
strapi2.log.info(`User ${userByPhone.username} already linked to Firebase (race condition handled)`);
|
|
30241
|
+
const existingLink = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(firebaseUID);
|
|
30242
|
+
if (existingLink && existingLink.user) {
|
|
30243
|
+
validateUserNotBlocked(existingLink.user);
|
|
30244
|
+
return existingLink.user;
|
|
30282
30245
|
}
|
|
30246
|
+
await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByPhone.documentId, { firebaseUserID: firebaseUID });
|
|
30247
|
+
strapi2.log.info(`Auto-linked phone user ${userByPhone.username} to Firebase UID ${firebaseUID}`);
|
|
30283
30248
|
return userByPhone;
|
|
30284
30249
|
}
|
|
30285
30250
|
}
|
|
@@ -30306,12 +30271,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30306
30271
|
type: "plugin",
|
|
30307
30272
|
name: "users-permissions"
|
|
30308
30273
|
});
|
|
30309
|
-
const
|
|
30274
|
+
const settings = await pluginStore.get({
|
|
30310
30275
|
key: "advanced"
|
|
30311
30276
|
});
|
|
30312
|
-
const role = await strapi2.db.query("plugin::users-permissions.role").findOne({ where: { type:
|
|
30277
|
+
const role = await strapi2.db.query("plugin::users-permissions.role").findOne({ where: { type: settings.default_role } });
|
|
30313
30278
|
userPayload.role = role.id;
|
|
30314
30279
|
userPayload.confirmed = true;
|
|
30280
|
+
userPayload.provider = "firebase";
|
|
30315
30281
|
userPayload.email = decodedToken.email;
|
|
30316
30282
|
userPayload.phoneNumber = decodedToken.phone_number;
|
|
30317
30283
|
if (profileMetaData) {
|
|
@@ -30347,7 +30313,22 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30347
30313
|
strapi2.log.info(`Created user ${newUser.username} and linked to Firebase UID ${decodedToken.uid}`);
|
|
30348
30314
|
return newUser;
|
|
30349
30315
|
} catch (error2) {
|
|
30350
|
-
if (
|
|
30316
|
+
if (error2.code === "23505") {
|
|
30317
|
+
strapi2.log.warn(
|
|
30318
|
+
`[Race Condition] User creation conflict for Firebase UID ${decodedToken.uid}. Another concurrent request created the user first. Retrying lookup...`
|
|
30319
|
+
);
|
|
30320
|
+
const existingUser = await strapi2.plugin("firebase-authentication").service("firebaseService").checkIfUserExists(decodedToken);
|
|
30321
|
+
if (existingUser) {
|
|
30322
|
+
strapi2.log.info(
|
|
30323
|
+
`[Race Condition] Successfully found user ${existingUser.username} created by concurrent request`
|
|
30324
|
+
);
|
|
30325
|
+
return existingUser;
|
|
30326
|
+
}
|
|
30327
|
+
strapi2.log.error(
|
|
30328
|
+
`[Race Condition] Failed to find user after race condition retry for Firebase UID ${decodedToken.uid}`
|
|
30329
|
+
);
|
|
30330
|
+
}
|
|
30331
|
+
if (error2.code !== "23505" && newUser) {
|
|
30351
30332
|
try {
|
|
30352
30333
|
await strapi2.db.query("plugin::users-permissions.user").delete({
|
|
30353
30334
|
where: { documentId: newUser.documentId }
|
|
@@ -30483,7 +30464,7 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30483
30464
|
},
|
|
30484
30465
|
/**
|
|
30485
30466
|
* Forgot password flow - sends reset email
|
|
30486
|
-
* Public endpoint that
|
|
30467
|
+
* Public endpoint that sends a Firebase-hosted password reset email using Firebase's secure hosted UI
|
|
30487
30468
|
*/
|
|
30488
30469
|
forgotPassword: async (ctx) => {
|
|
30489
30470
|
const { email: email2 } = ctx.request.body;
|
|
@@ -30529,13 +30510,30 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30529
30510
|
if (!strapiUser) {
|
|
30530
30511
|
return { message: "If an account with that email exists, a password reset link has been sent." };
|
|
30531
30512
|
}
|
|
30532
|
-
const
|
|
30533
|
-
|
|
30534
|
-
|
|
30535
|
-
|
|
30536
|
-
|
|
30537
|
-
)
|
|
30538
|
-
|
|
30513
|
+
const actionCodeSettings = {
|
|
30514
|
+
url: resetUrl,
|
|
30515
|
+
// Continue URL after reset completes on Firebase's page
|
|
30516
|
+
handleCodeInApp: false
|
|
30517
|
+
};
|
|
30518
|
+
const timeoutPromise = new Promise((_2, reject) => {
|
|
30519
|
+
setTimeout(
|
|
30520
|
+
() => reject(new Error("Firebase generatePasswordResetLink timeout after 10 seconds")),
|
|
30521
|
+
1e4
|
|
30522
|
+
);
|
|
30523
|
+
});
|
|
30524
|
+
let resetLink;
|
|
30525
|
+
try {
|
|
30526
|
+
resetLink = await Promise.race([
|
|
30527
|
+
strapi2.firebase.auth().generatePasswordResetLink(strapiUser.email, actionCodeSettings),
|
|
30528
|
+
timeoutPromise
|
|
30529
|
+
]);
|
|
30530
|
+
strapi2.log.info(
|
|
30531
|
+
`✅ Password reset link generated successfully for ${strapiUser.email}: ${resetLink}`
|
|
30532
|
+
);
|
|
30533
|
+
} catch (error2) {
|
|
30534
|
+
strapi2.log.error(`❌ Failed to generate password reset link for ${strapiUser.email}:`, error2);
|
|
30535
|
+
throw error2;
|
|
30536
|
+
}
|
|
30539
30537
|
await strapi2.plugin("firebase-authentication").service("emailService").sendPasswordResetEmail(strapiUser, resetLink);
|
|
30540
30538
|
return {
|
|
30541
30539
|
message: "If an account with that email exists, a password reset link has been sent."
|
|
@@ -30549,7 +30547,17 @@ const firebaseService = ({ strapi: strapi2 }) => ({
|
|
|
30549
30547
|
},
|
|
30550
30548
|
/**
|
|
30551
30549
|
* Reset password with authenticated JWT
|
|
30552
|
-
*
|
|
30550
|
+
* Allows authenticated users (or admins) to change a user's Firebase password
|
|
30551
|
+
*
|
|
30552
|
+
* @param ctx - Koa context with JWT in Authorization header and new password in body
|
|
30553
|
+
* @returns User object and fresh JWT for auto-login
|
|
30554
|
+
*
|
|
30555
|
+
* @remarks
|
|
30556
|
+
* Use cases:
|
|
30557
|
+
* 1. Admin-initiated password reset (via admin panel)
|
|
30558
|
+
* 2. User-initiated password change (when already authenticated)
|
|
30559
|
+
*
|
|
30560
|
+
* NOT used for forgot password email flow - that now uses Firebase's hosted UI
|
|
30553
30561
|
*/
|
|
30554
30562
|
resetPassword: async (ctx) => {
|
|
30555
30563
|
const { password } = ctx.request.body;
|
|
@@ -31284,7 +31292,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
|
|
|
31284
31292
|
if (!userId || typeof userId !== "string") {
|
|
31285
31293
|
throw new Error("Invalid user documentId");
|
|
31286
31294
|
}
|
|
31287
|
-
let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").
|
|
31295
|
+
let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
|
|
31288
31296
|
filters: { user: { documentId: { $eq: userId } } },
|
|
31289
31297
|
populate: ["user"]
|
|
31290
31298
|
});
|
|
@@ -31299,7 +31307,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
|
|
|
31299
31307
|
* @returns Firebase user data with populated user
|
|
31300
31308
|
*/
|
|
31301
31309
|
async getByFirebaseUID(firebaseUID) {
|
|
31302
|
-
return await strapi2.documents("plugin::firebase-authentication.firebase-user-data").
|
|
31310
|
+
return await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
|
|
31303
31311
|
filters: { firebaseUserID: { $eq: firebaseUID } },
|
|
31304
31312
|
populate: ["user"]
|
|
31305
31313
|
});
|
|
@@ -31310,7 +31318,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
|
|
|
31310
31318
|
* @param data - Fields to update
|
|
31311
31319
|
*/
|
|
31312
31320
|
async updateForUser(userId, data) {
|
|
31313
|
-
let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").
|
|
31321
|
+
let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
|
|
31314
31322
|
filters: { user: { documentId: { $eq: userId } } }
|
|
31315
31323
|
});
|
|
31316
31324
|
if (!firebaseData) {
|
|
@@ -31326,8 +31334,8 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
|
|
|
31326
31334
|
});
|
|
31327
31335
|
} catch (error2) {
|
|
31328
31336
|
if (error2.code === "23505") {
|
|
31329
|
-
strapi2.log.warn(`Race condition detected for user ${userId}, retrying
|
|
31330
|
-
firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").
|
|
31337
|
+
strapi2.log.warn(`Race condition detected for user ${userId}, retrying findFirst`);
|
|
31338
|
+
firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
|
|
31331
31339
|
filters: { user: { documentId: { $eq: userId } } }
|
|
31332
31340
|
});
|
|
31333
31341
|
if (firebaseData) {
|