customer-registration 0.0.112 → 0.0.113
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/.medusa/server/src/api/auth/customer/emailpass/reset-password/route.js +1 -26
- package/.medusa/server/src/api/auth/customer/emailpass/route.js +19 -97
- package/.medusa/server/src/api/auth/customer/phonepass/register/route.js +50 -0
- package/.medusa/server/src/api/auth/customer/phonepass/route.js +105 -0
- package/.medusa/server/src/api/middlewares/{block-pending-customer.js → guard-account-deletion.js} +4 -4
- package/.medusa/server/src/api/middlewares/ip-rate-limit.js +48 -0
- package/.medusa/server/src/api/middlewares/validate-customer-registration.js +60 -0
- package/.medusa/server/src/api/middlewares.js +17 -4
- package/.medusa/server/src/api/store/customers/account-deletion/cancel-request/route.js +16 -6
- package/.medusa/server/src/api/store/customers/account-deletion/validators.js +11 -3
- package/.medusa/server/src/api/store/customers/me/contact/route.js +95 -0
- package/.medusa/server/src/api/store/customers/me/contact/verify/route.js +83 -0
- package/.medusa/server/src/api/store/customers/me/route.js +53 -0
- package/.medusa/server/src/api/store/customers/otp/send/route.js +1 -6
- package/.medusa/server/src/api/store/customers/otp/verify/route.js +95 -3
- package/.medusa/server/src/api/store/customers/route.js +89 -0
- package/.medusa/server/src/config.js +32 -23
- package/.medusa/server/src/modules/otp-verification/service.js +72 -1
- package/.medusa/server/src/providers/phonepass/index.js +9 -0
- package/.medusa/server/src/providers/phonepass/service.js +133 -0
- package/.medusa/server/src/subscribers/password-reset.js +1 -42
- package/.medusa/server/src/workflows/change-password.js +40 -64
- package/.medusa/server/src/workflows/send-contact-change-otp-workflow.js +41 -0
- package/.medusa/server/src/workflows/steps/determine-contact-method-step.js +8 -2
- package/.medusa/server/src/workflows/steps/generate-contact-change-otp-step.js +24 -0
- package/.medusa/server/src/workflows/steps/index.js +6 -2
- package/.medusa/server/src/workflows/steps/send-notification-step.js +1 -11
- package/.medusa/server/src/workflows/steps/sync-phonepass-entity-id-step.js +63 -0
- package/.medusa/server/src/workflows/steps/update-password-step.js +21 -29
- package/.medusa/server/src/workflows/update-contact-workflow.js +100 -0
- package/.medusa/server/src/workflows/verify-phone.js +11 -4
- package/README.md +363 -223
- package/package.json +3 -1
- package/.medusa/server/src/subscribers/customer-updated.js +0 -100
|
@@ -24,7 +24,6 @@ function htmlToPlainText(html) {
|
|
|
24
24
|
* Send password reset email using notification service
|
|
25
25
|
*/
|
|
26
26
|
async function sendPasswordResetEmail(email, token, resetUrl, templatePath, subject, container) {
|
|
27
|
-
console.log("[reset-password] Sending password reset email directly...");
|
|
28
27
|
const notificationService = container.resolve(utils_1.Modules.NOTIFICATION);
|
|
29
28
|
if (!notificationService) {
|
|
30
29
|
console.error("[reset-password] Notification service is not configured");
|
|
@@ -61,41 +60,18 @@ async function sendPasswordResetEmail(email, token, resetUrl, templatePath, subj
|
|
|
61
60
|
template: htmlContent, // Some providers expect 'template' field
|
|
62
61
|
subject, // Include subject at root level too
|
|
63
62
|
};
|
|
64
|
-
// Log payload structure (sanitized for security)
|
|
65
|
-
console.log("[reset-password] Email payload structure:", {
|
|
66
|
-
to: payload.to,
|
|
67
|
-
channel: payload.channel,
|
|
68
|
-
subject: payload.subject,
|
|
69
|
-
hasHtml: !!payload.html,
|
|
70
|
-
hasText: !!payload.text,
|
|
71
|
-
hasBody: !!payload.body,
|
|
72
|
-
hasTemplate: !!payload.template,
|
|
73
|
-
dataKeys: Object.keys(payload.data || {}),
|
|
74
|
-
htmlLength: payload.html?.length || 0,
|
|
75
|
-
textLength: payload.text?.length || 0,
|
|
76
|
-
});
|
|
77
63
|
try {
|
|
78
64
|
if (typeof notificationService.create === "function") {
|
|
79
|
-
console.log("[reset-password] Using notificationService.create method");
|
|
80
65
|
await notificationService.create(payload);
|
|
81
|
-
console.log(`[reset-password] ✓ Password reset email sent successfully to ${email}`);
|
|
82
66
|
}
|
|
83
67
|
else if (typeof notificationService.createNotifications === "function") {
|
|
84
|
-
console.log("[reset-password] Using notificationService.createNotifications method");
|
|
85
68
|
await notificationService.createNotifications([payload]);
|
|
86
|
-
console.log(`[reset-password] ✓ Password reset email sent successfully to ${email}`);
|
|
87
69
|
}
|
|
88
70
|
else {
|
|
89
|
-
console.error("[reset-password] Notification service does not support sending notifications");
|
|
90
71
|
}
|
|
91
72
|
}
|
|
92
73
|
catch (error) {
|
|
93
|
-
console.error(`[reset-password] Failed to send password reset email to ${email}:`, error);
|
|
94
74
|
if (error instanceof Error) {
|
|
95
|
-
console.error("[reset-password] Error details:", {
|
|
96
|
-
message: error.message,
|
|
97
|
-
stack: error.stack,
|
|
98
|
-
});
|
|
99
75
|
}
|
|
100
76
|
throw error;
|
|
101
77
|
}
|
|
@@ -187,7 +163,6 @@ const POST = async (req, res) => {
|
|
|
187
163
|
await sendPasswordResetEmail(normalizedEmail, resetToken, resetUrl || "", pluginOptions.password_reset.template, pluginOptions.password_reset.subject, req.scope);
|
|
188
164
|
}
|
|
189
165
|
catch (emailError) {
|
|
190
|
-
console.error("[reset-password] Failed to send email:", emailError);
|
|
191
166
|
// Continue anyway - don't reveal if email exists
|
|
192
167
|
}
|
|
193
168
|
// Return 201 (Created) to match Medusa's built-in route response
|
|
@@ -201,4 +176,4 @@ const POST = async (req, res) => {
|
|
|
201
176
|
}
|
|
202
177
|
};
|
|
203
178
|
exports.POST = POST;
|
|
204
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
179
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvZW1haWxwYXNzL3Jlc2V0LXBhc3N3b3JkL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUEyRjtBQUUzRiwyRkFBb0c7QUFDcEcsOEVBQStFO0FBQy9FLGtEQUc4QjtBQUU5Qjs7R0FFRztBQUNILFNBQVMsZUFBZSxDQUFDLElBQVk7SUFDbkMsT0FBTyxJQUFJO1NBQ1IsT0FBTyxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsQ0FBQyxtQkFBbUI7U0FDM0MsT0FBTyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUMsQ0FBQyw0QkFBNEI7U0FDcEQsT0FBTyxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsQ0FBQyx1QkFBdUI7U0FDOUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQyxzQkFBc0I7U0FDNUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQyxzQkFBc0I7U0FDNUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUMsQ0FBQyx3QkFBd0I7U0FDaEQsT0FBTyxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsQ0FBQyx1QkFBdUI7U0FDOUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQyw2QkFBNkI7U0FDekQsSUFBSSxFQUFFLENBQUE7QUFDWCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxLQUFLLFVBQVUsc0JBQXNCLENBQ25DLEtBQWEsRUFDYixLQUFhLEVBQ2IsUUFBZ0IsRUFDaEIsWUFBb0IsRUFDcEIsT0FBZSxFQUNmLFNBQWM7SUFHZCxNQUFNLG1CQUFtQixHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLFlBQVksQ0FHakUsQ0FBQTtJQUVELElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQ3pCLE9BQU8sQ0FBQyxL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
|
|
@@ -5,14 +5,13 @@ const utils_1 = require("@medusajs/framework/utils");
|
|
|
5
5
|
const generate_jwt_token_1 = require("@medusajs/medusa/api/auth/utils/generate-jwt-token");
|
|
6
6
|
const account_deletion_request_1 = require("../../../../modules/account-deletion-request");
|
|
7
7
|
const otp_verification_1 = require("../../../../modules/otp-verification");
|
|
8
|
+
const config_1 = require("../../../../config");
|
|
8
9
|
const GET = async (req, res) => {
|
|
9
|
-
console.log("[emailpass-auth] Authentication request received", {
|
|
10
|
-
method: req.method,
|
|
11
|
-
url: req.url,
|
|
12
|
-
hasBody: !!req.body,
|
|
13
|
-
hasQuery: !!req.query,
|
|
14
|
-
});
|
|
15
10
|
const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
|
|
11
|
+
const loginOptions = (0, config_1.resolveCustomerRegistrationOptions)(config);
|
|
12
|
+
if (loginOptions.login.identifier === "phone") {
|
|
13
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Email login is not enabled. Please log in with your phone number.");
|
|
14
|
+
}
|
|
16
15
|
const service = req.scope.resolve(utils_1.Modules.AUTH);
|
|
17
16
|
const authData = {
|
|
18
17
|
url: req.url,
|
|
@@ -22,28 +21,11 @@ const GET = async (req, res) => {
|
|
|
22
21
|
protocol: req.protocol,
|
|
23
22
|
};
|
|
24
23
|
const { success, error, authIdentity, location } = await service.authenticate("emailpass", authData);
|
|
25
|
-
console.log("[emailpass-auth] Authentication result", {
|
|
26
|
-
success,
|
|
27
|
-
hasError: !!error,
|
|
28
|
-
error,
|
|
29
|
-
hasAuthIdentity: !!authIdentity,
|
|
30
|
-
authIdentityId: authIdentity?.id,
|
|
31
|
-
hasLocation: !!location,
|
|
32
|
-
});
|
|
33
24
|
if (location) {
|
|
34
|
-
console.log("[emailpass-auth] Redirecting to location", { location });
|
|
35
25
|
return res.status(200).json({ location });
|
|
36
26
|
}
|
|
37
27
|
if (success && authIdentity) {
|
|
38
28
|
const email = authIdentity.provider_identities?.[0]?.entity_id ?? "";
|
|
39
|
-
console.log("[emailpass-auth] Processing successful authentication", {
|
|
40
|
-
email,
|
|
41
|
-
authIdentityId: authIdentity.id,
|
|
42
|
-
hasProviderIdentities: !!authIdentity.provider_identities,
|
|
43
|
-
providerIdentitiesCount: authIdentity.provider_identities?.length || 0,
|
|
44
|
-
hasAppMetadata: !!authIdentity.app_metadata,
|
|
45
|
-
appMetadataCustomerId: authIdentity.app_metadata?.customer_id,
|
|
46
|
-
});
|
|
47
29
|
await enforceEmailAndPhoneVerification({
|
|
48
30
|
email,
|
|
49
31
|
req,
|
|
@@ -51,37 +33,18 @@ const GET = async (req, res) => {
|
|
|
51
33
|
// Ensure authIdentity has customer_id in app_metadata
|
|
52
34
|
// The generateJwtTokenForAuthIdentity function requires app_metadata.customer_id
|
|
53
35
|
let customerId = authIdentity.app_metadata?.customer_id;
|
|
54
|
-
console.log("[emailpass-auth] Checking customer ID", {
|
|
55
|
-
email,
|
|
56
|
-
customerIdFromMetadata: customerId,
|
|
57
|
-
hasAppMetadata: !!authIdentity.app_metadata,
|
|
58
|
-
});
|
|
59
36
|
if (!customerId) {
|
|
60
37
|
// Try to get customer_id from provider_identity entity_id (email)
|
|
61
38
|
// and look up the customer
|
|
62
|
-
console.log("[emailpass-auth] Customer ID not in metadata, looking up by email", {
|
|
63
|
-
email: email.toLowerCase(),
|
|
64
|
-
});
|
|
65
39
|
const customerModule = req.scope.resolve(utils_1.Modules.CUSTOMER);
|
|
66
40
|
const customers = await customerModule.listCustomers({
|
|
67
41
|
email: email.toLowerCase(),
|
|
68
42
|
});
|
|
69
|
-
console.log("[emailpass-auth] Customer lookup result", {
|
|
70
|
-
email: email.toLowerCase(),
|
|
71
|
-
customersFound: customers?.length || 0,
|
|
72
|
-
customerId: customers && customers.length > 0 ? customers[0].id : null,
|
|
73
|
-
});
|
|
74
43
|
if (customers && customers.length > 0) {
|
|
75
44
|
customerId = customers[0].id;
|
|
76
45
|
}
|
|
77
46
|
}
|
|
78
47
|
if (!customerId) {
|
|
79
|
-
console.error("[emailpass-auth] Unable to determine customer ID", {
|
|
80
|
-
email,
|
|
81
|
-
hasAppMetadata: !!authIdentity.app_metadata,
|
|
82
|
-
appMetadata: authIdentity.app_metadata,
|
|
83
|
-
providerIdentities: authIdentity.provider_identities,
|
|
84
|
-
});
|
|
85
48
|
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Unable to determine customer ID for authentication");
|
|
86
49
|
}
|
|
87
50
|
const accountDeletionService = req.scope.resolve(account_deletion_request_1.ACCOUNT_DELETION_REQUEST_MODULE);
|
|
@@ -105,20 +68,6 @@ const GET = async (req, res) => {
|
|
|
105
68
|
});
|
|
106
69
|
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "JWT secret is not configured");
|
|
107
70
|
}
|
|
108
|
-
// Log before token generation
|
|
109
|
-
console.log("[emailpass-auth] Generating JWT token", {
|
|
110
|
-
email,
|
|
111
|
-
customerId,
|
|
112
|
-
authIdentityId: authIdentityWithCustomerId?.id,
|
|
113
|
-
actorType: "customer",
|
|
114
|
-
jwtSecretExists: !!http.jwtSecret,
|
|
115
|
-
jwtSecretType: typeof http.jwtSecret,
|
|
116
|
-
jwtSecretHasLength: typeof http.jwtSecret === "string" ? !!http.jwtSecret.length : false,
|
|
117
|
-
jwtSecretLength: typeof http.jwtSecret === "string" ? http.jwtSecret.length : undefined,
|
|
118
|
-
jwtExpiresIn: http.jwtExpiresIn || "7d",
|
|
119
|
-
hasAppMetadata: !!authIdentityWithCustomerId?.app_metadata,
|
|
120
|
-
appMetadataCustomerId: authIdentityWithCustomerId?.app_metadata?.customer_id,
|
|
121
|
-
});
|
|
122
71
|
let token;
|
|
123
72
|
try {
|
|
124
73
|
token = await (0, generate_jwt_token_1.generateJwtTokenForAuthIdentity)({
|
|
@@ -139,38 +88,10 @@ const GET = async (req, res) => {
|
|
|
139
88
|
});
|
|
140
89
|
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `JWT generation failed: ${jwtError instanceof Error ? jwtError.message : "Unknown error"}`);
|
|
141
90
|
}
|
|
142
|
-
// Log token generation result
|
|
143
|
-
console.log("[emailpass-auth] JWT token generation result", {
|
|
144
|
-
email,
|
|
145
|
-
customerId,
|
|
146
|
-
tokenExists: !!token,
|
|
147
|
-
tokenType: typeof token,
|
|
148
|
-
tokenLength: typeof token === "string" ? token.length : 0,
|
|
149
|
-
tokenPreview: typeof token === "string" ? token.substring(0, 20) + "..." : "N/A",
|
|
150
|
-
});
|
|
151
91
|
// Validate token was generated successfully
|
|
152
92
|
if (!token || typeof token !== "string") {
|
|
153
|
-
console.error("[emailpass-auth] Invalid token generated", {
|
|
154
|
-
email,
|
|
155
|
-
customerId,
|
|
156
|
-
token,
|
|
157
|
-
tokenType: typeof token,
|
|
158
|
-
tokenValue: token,
|
|
159
|
-
jwtSecretExists: !!http.jwtSecret,
|
|
160
|
-
authIdentityId: authIdentityWithCustomerId?.id,
|
|
161
|
-
authIdentityStructure: {
|
|
162
|
-
id: authIdentityWithCustomerId?.id,
|
|
163
|
-
provider_identities: authIdentityWithCustomerId?.provider_identities?.length,
|
|
164
|
-
app_metadata: authIdentityWithCustomerId?.app_metadata,
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
93
|
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `Failed to generate authentication token for customer ${customerId}. Token type: ${typeof token}, Token value: ${token}`);
|
|
168
94
|
}
|
|
169
|
-
console.log("[emailpass-auth] Authentication successful, returning token", {
|
|
170
|
-
email,
|
|
171
|
-
customerId,
|
|
172
|
-
tokenLength: token.length,
|
|
173
|
-
});
|
|
174
95
|
return res.status(200).json({ token });
|
|
175
96
|
}
|
|
176
97
|
console.error("[emailpass-auth] Authentication failed", {
|
|
@@ -186,21 +107,22 @@ const POST = async (req, res) => {
|
|
|
186
107
|
};
|
|
187
108
|
exports.POST = POST;
|
|
188
109
|
const enforceEmailAndPhoneVerification = async ({ email, req, }) => {
|
|
189
|
-
|
|
190
|
-
|
|
110
|
+
// Read identifier + require_verification from plugin config
|
|
111
|
+
const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
|
|
112
|
+
const options = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
|
|
113
|
+
const { identifier, require_verification } = options.registration;
|
|
114
|
+
// If verification is disabled entirely, skip all checks
|
|
115
|
+
if (!require_verification) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
191
118
|
const otpService = req.scope.resolve(otp_verification_1.OTP_VERIFICATION_MODULE);
|
|
192
119
|
const verificationStatus = await otpService.getCustomerVerificationByEmail(req.scope, email);
|
|
193
|
-
|
|
194
|
-
email,
|
|
195
|
-
email_verified: verificationStatus.email_verified,
|
|
196
|
-
verificationStatus,
|
|
197
|
-
});
|
|
198
|
-
if (!verificationStatus.email_verified) {
|
|
199
|
-
console.error("[emailpass-auth] Email not verified", {
|
|
200
|
-
email,
|
|
201
|
-
verificationStatus,
|
|
202
|
-
});
|
|
120
|
+
if ((identifier === "email" || identifier === "both") && !verificationStatus.email_verified) {
|
|
203
121
|
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Email not verified.");
|
|
204
122
|
}
|
|
123
|
+
if ((identifier === "phone" || identifier === "both") && !verificationStatus.phone_verified) {
|
|
124
|
+
console.error("[emailpass-auth] Phone not verified", { email });
|
|
125
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Phone not verified.");
|
|
126
|
+
}
|
|
205
127
|
};
|
|
206
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
128
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvZW1haWxwYXNzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQU1BLHFEQUlrQztBQUNsQywyRkFBb0c7QUFDcEcsMkZBQThGO0FBRTlGLDJFQUE4RTtBQUk5RSwrQ0FHMkI7QUFFcEIsTUFBTSxHQUFHLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ25FLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUM5QixpQ0FBeUIsQ0FBQyxhQUFhLENBQ3hDLENBQUE7SUFFRCxNQUFNLFlBQVksR0FBRyxJQUFBLDJDQUFrQyxFQUFDLE1BQTJCLENBQUMsQ0FBQTtJQUNwRixJQUFJLFlBQVksQ0FBQyxLQUFLLENBQUMsVUFBVSxLQUFLLE9BQU8sRUFBRSxDQUFDO1FBQzlDLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG1FQUFtRSxDQUNwRSxDQUFBO0lBQ0gsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUUvQyxNQUFNLFFBQVEsR0FBRztRQUNmLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRztRQUNaLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztRQUNwQixLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7UUFDaEIsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO1FBQ2QsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRO0tBQ0EsQ0FBQTtJQUV4QixNQUFNLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLEdBQzlDLE1BQU0sT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVB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
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.POST = void 0;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const generate_jwt_token_1 = require("@medusajs/medusa/api/auth/utils/generate-jwt-token");
|
|
6
|
+
/**
|
|
7
|
+
* Register a new customer with phone + password.
|
|
8
|
+
*
|
|
9
|
+
* On success the caller receives a short-lived JWT token. Use it as the
|
|
10
|
+
* Bearer token when calling `POST /store/customers` to create the customer
|
|
11
|
+
* record and link it to this auth identity.
|
|
12
|
+
*/
|
|
13
|
+
const POST = async (req, res) => {
|
|
14
|
+
const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
|
|
15
|
+
const service = req.scope.resolve(utils_1.Modules.AUTH);
|
|
16
|
+
const authData = {
|
|
17
|
+
url: req.url,
|
|
18
|
+
headers: req.headers,
|
|
19
|
+
query: req.query,
|
|
20
|
+
body: req.body,
|
|
21
|
+
protocol: req.protocol,
|
|
22
|
+
};
|
|
23
|
+
const { success, error, authIdentity } = await service.register("phonepass", authData);
|
|
24
|
+
if (!success || !authIdentity) {
|
|
25
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, error || "Registration failed");
|
|
26
|
+
}
|
|
27
|
+
const { http } = config.projectConfig;
|
|
28
|
+
if (!http.jwtSecret) {
|
|
29
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "JWT secret is not configured");
|
|
30
|
+
}
|
|
31
|
+
let token;
|
|
32
|
+
try {
|
|
33
|
+
token = await (0, generate_jwt_token_1.generateJwtTokenForAuthIdentity)({
|
|
34
|
+
authIdentity,
|
|
35
|
+
actorType: "customer",
|
|
36
|
+
}, {
|
|
37
|
+
secret: http.jwtSecret,
|
|
38
|
+
expiresIn: http.jwtExpiresIn || "7d",
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (jwtError) {
|
|
42
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `JWT generation failed: ${jwtError instanceof Error ? jwtError.message : "Unknown error"}`);
|
|
43
|
+
}
|
|
44
|
+
if (!token || typeof token !== "string") {
|
|
45
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to generate registration token");
|
|
46
|
+
}
|
|
47
|
+
return res.status(200).json({ token });
|
|
48
|
+
};
|
|
49
|
+
exports.POST = POST;
|
|
50
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvcGhvbmVwYXNzL3JlZ2lzdGVyL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLHFEQUlrQztBQUNsQywyRkFBb0c7QUFFcEc7Ozs7OztHQU1HO0FBQ0ksTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBQ3pFLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUUvQyxNQUFNLFFBQVEsR0FBRztRQUNmLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRztRQUNaLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztRQUNwQixLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7UUFDaEIsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO1FBQ2QsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRO0tBQ0EsQ0FBQTtJQUV4QixNQUFNLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxRQUFRLENBQzdELFdBQVcsRUFDWCxRQUFRLENBQ1QsQ0FBQTtJQUVELElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUM5QixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixLQUFLLElBQUkscUJBQXFCLENBQy9CLENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxhQUFhLENBQUE7SUFFckMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNwQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw4QkFBOEIsQ0FDL0IsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLEtBQXlCLENBQUE7SUFDN0IsSUFBSSxDQUFDO1FBQ0gsS0FBSyxHQUFHLE1BQU0sSUFBQSxvREFBK0IsRUFDM0M7WUFDRSxZQUFZO1lBQ1osU0FBUyxFQUFFLFVBQVU7U0FDdEIsRUFDRDtZQUNFLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUztZQUN0QixTQUFTLEVBQUUsSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJO1NBQ3JDLENBQ0YsQ0FBQTtJQUNILENBQUM7SUFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO1FBQ2xCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFDbEMsMEJBQTBCLFFBQVEsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGVBQWUsRUFBRSxDQUMzRixDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksQ0FBQyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDeEMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLGdCQUFnQixFQUNsQyx1Q0FBdUMsQ0FDeEMsQ0FBQTtJQUNILENBQUM7SUFFRCxPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQTtBQUN4QyxDQUFDLENBQUE7QUE1RFksUUFBQSxJQUFJLFFBNERoQiJ9
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.POST = void 0;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const generate_jwt_token_1 = require("@medusajs/medusa/api/auth/utils/generate-jwt-token");
|
|
6
|
+
const account_deletion_request_1 = require("../../../../modules/account-deletion-request");
|
|
7
|
+
const otp_verification_1 = require("../../../../modules/otp-verification");
|
|
8
|
+
const config_1 = require("../../../../config");
|
|
9
|
+
const POST = async (req, res) => {
|
|
10
|
+
const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
|
|
11
|
+
const loginOptions = (0, config_1.resolveCustomerRegistrationOptions)(config);
|
|
12
|
+
if (loginOptions.login.identifier === "email") {
|
|
13
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Phone login is not enabled. Please log in with your email.");
|
|
14
|
+
}
|
|
15
|
+
const service = req.scope.resolve(utils_1.Modules.AUTH);
|
|
16
|
+
const authData = {
|
|
17
|
+
url: req.url,
|
|
18
|
+
headers: req.headers,
|
|
19
|
+
query: req.query,
|
|
20
|
+
body: req.body,
|
|
21
|
+
protocol: req.protocol,
|
|
22
|
+
};
|
|
23
|
+
const { success, error, authIdentity } = await service.authenticate("phonepass", authData);
|
|
24
|
+
if (success && authIdentity) {
|
|
25
|
+
const phone = authIdentity.provider_identities?.[0]?.entity_id ?? "";
|
|
26
|
+
await enforcePhoneVerification({ authIdentity, req });
|
|
27
|
+
let customerId = authIdentity.app_metadata?.customer_id;
|
|
28
|
+
if (!customerId) {
|
|
29
|
+
const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
|
|
30
|
+
if (knex) {
|
|
31
|
+
const result = await knex.raw(`SELECT id FROM customer WHERE phone = ? LIMIT 1`, [phone]);
|
|
32
|
+
const row = result.rows?.[0] ?? result[0]?.[0];
|
|
33
|
+
if (row?.id) {
|
|
34
|
+
customerId = row.id;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!customerId) {
|
|
39
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Unable to determine customer ID for authentication");
|
|
40
|
+
}
|
|
41
|
+
const accountDeletionService = req.scope.resolve(account_deletion_request_1.ACCOUNT_DELETION_REQUEST_MODULE);
|
|
42
|
+
if (await accountDeletionService.hasPendingRequest(customerId)) {
|
|
43
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Customer has an active account deletion request");
|
|
44
|
+
}
|
|
45
|
+
const authIdentityWithCustomerId = {
|
|
46
|
+
...authIdentity,
|
|
47
|
+
app_metadata: {
|
|
48
|
+
...authIdentity.app_metadata,
|
|
49
|
+
customer_id: customerId,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
const { http } = config.projectConfig;
|
|
53
|
+
if (!http.jwtSecret) {
|
|
54
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "JWT secret is not configured");
|
|
55
|
+
}
|
|
56
|
+
let token;
|
|
57
|
+
try {
|
|
58
|
+
token = await (0, generate_jwt_token_1.generateJwtTokenForAuthIdentity)({
|
|
59
|
+
authIdentity: authIdentityWithCustomerId,
|
|
60
|
+
actorType: "customer",
|
|
61
|
+
}, {
|
|
62
|
+
secret: http.jwtSecret,
|
|
63
|
+
expiresIn: http.jwtExpiresIn || "7d",
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (jwtError) {
|
|
67
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `JWT generation failed: ${jwtError instanceof Error ? jwtError.message : "Unknown error"}`);
|
|
68
|
+
}
|
|
69
|
+
if (!token || typeof token !== "string") {
|
|
70
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to generate authentication token");
|
|
71
|
+
}
|
|
72
|
+
return res.status(200).json({ token });
|
|
73
|
+
}
|
|
74
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, error || "Authentication failed");
|
|
75
|
+
};
|
|
76
|
+
exports.POST = POST;
|
|
77
|
+
const enforcePhoneVerification = async ({ authIdentity, req, }) => {
|
|
78
|
+
const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
|
|
79
|
+
const options = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
|
|
80
|
+
const { require_verification } = options.registration;
|
|
81
|
+
if (!require_verification) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Use customer_id — not phone — for the verification lookup.
|
|
85
|
+
// Phone is mutable: after a phone update customer.phone becomes the NEW number
|
|
86
|
+
// while provider_identity.entity_id still holds the OLD one. Querying
|
|
87
|
+
// WHERE phone = entity_id would find no row and return phone_verified = false
|
|
88
|
+
// even when the customer's actual record is marked verified.
|
|
89
|
+
const customerId = authIdentity.app_metadata?.customer_id;
|
|
90
|
+
if (!customerId) {
|
|
91
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Phone not verified.");
|
|
92
|
+
}
|
|
93
|
+
const otpService = req.scope.resolve(otp_verification_1.OTP_VERIFICATION_MODULE);
|
|
94
|
+
const verificationStatus = await otpService.getCustomerVerificationByCustomerId(req.scope, customerId);
|
|
95
|
+
if (!verificationStatus.phone_verified) {
|
|
96
|
+
// Surface a helpful message when a phone change is pending verification
|
|
97
|
+
const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
|
|
98
|
+
const row = await knex.raw(`SELECT metadata->>'pending_phone' AS pending_phone FROM customer WHERE id = ? LIMIT 1`, [customerId]);
|
|
99
|
+
const pendingPhone = (row.rows?.[0] ?? row[0]?.[0])?.pending_phone ?? null;
|
|
100
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, pendingPhone
|
|
101
|
+
? "Your new phone number is pending verification. Please verify it to continue."
|
|
102
|
+
: "Phone not verified.");
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvcGhvbmVwYXNzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUtBLHFEQUlrQztBQUNsQywyRkFBb0c7QUFDcEcsMkZBQThGO0FBRTlGLDJFQUE4RTtBQUc5RSwrQ0FHMkI7QUFFcEIsTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBRXpFLE1BQU0sWUFBWSxHQUFHLElBQUEsMkNBQWtDLEVBQUMsTUFBMkIsQ0FBQyxDQUFBO0lBQ3BGLElBQUksWUFBWSxDQUFDLEtBQUssQ0FBQyxVQUFVLEtBQUssT0FBTyxFQUFFLENBQUM7UUFDOUMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsNERBQTRELENBQzdELENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLElBQUksQ0FBQyxDQUFBO0lBRS9DLE1BQU0sUUFBUSxHQUFHO1FBQ2YsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHO1FBQ1osT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPO1FBQ3BCLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSztRQUNoQixJQUFJLEVBQUUsR0FBRyxDQUFDLElBQUk7UUFDZCxRQUFRLEVBQUUsR0FBRyxDQUFDLFFBQVE7S0FDQSxDQUFBO0lBRXhCLE1BQU0sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxHQUNwQyxNQUFNLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLFFBQVEsQ0FB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
|
package/.medusa/server/src/api/middlewares/{block-pending-customer.js → guard-account-deletion.js}
RENAMED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.guardAccountDeletion = guardAccountDeletion;
|
|
4
4
|
const utils_1 = require("@medusajs/framework/utils");
|
|
5
5
|
const account_deletion_request_1 = require("../../modules/account-deletion-request");
|
|
6
|
-
/** Paths under /store that a customer with pending deletion is allowed to call. */
|
|
6
|
+
/** Paths under /store that a customer with a pending deletion is allowed to call. */
|
|
7
7
|
const STORE_ACCOUNT_DELETION_PATH = "/store/customers/account-deletion/";
|
|
8
8
|
/**
|
|
9
9
|
* Blocks requests when the authenticated customer has an active account_deletion_request
|
|
10
10
|
* (status "pending" or "confirmed"). Login (auth) is allowed; all other store APIs are
|
|
11
11
|
* blocked except account-deletion routes (request, confirm, cancel-request, cancel-confirm).
|
|
12
12
|
*/
|
|
13
|
-
async function
|
|
13
|
+
async function guardAccountDeletion(req, res, next) {
|
|
14
14
|
const authContext = req.auth_context;
|
|
15
15
|
const customerId = authContext?.actor_id ?? authContext?.user_id;
|
|
16
16
|
if (!customerId) {
|
|
@@ -26,4 +26,4 @@ async function blockPendingCustomer(req, res, next) {
|
|
|
26
26
|
}
|
|
27
27
|
next();
|
|
28
28
|
}
|
|
29
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3VhcmQtYWNjb3VudC1kZWxldGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvbWlkZGxld2FyZXMvZ3VhcmQtYWNjb3VudC1kZWxldGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWlCQSxvREE2QkM7QUF6Q0QscURBQXVEO0FBQ3ZELHFGQUF3RjtBQUd4RixxRkFBcUY7QUFDckYsTUFBTSwyQkFBMkIsR0FBRyxvQ0FBb0MsQ0FBQTtBQUV4RTs7OztHQUlHO0FBQ0ksS0FBSyxVQUFVLG9CQUFvQixDQUN4QyxHQUFrQixFQUNsQixHQUFtQixFQUNuQixJQUF3QjtJQUV4QixNQUFNLFdBQVcsR0FBSSxHQUVuQixDQUFDLFlBQVksQ0FBQTtJQUNmLE1BQU0sVUFBVSxHQUFHLFdBQVcsRUFBRSxRQUFRLElBQUksV0FBVyxFQUFFLE9BQU8sQ0FBQTtJQUVoRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEIsT0FBTyxJQUFJLEVBQUUsQ0FBQTtJQUNmLENBQUM7SUFFRCxNQUFNLElBQUksR0FBSSxHQUF3QixDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFBO0lBQy9ELElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsQ0FBQyxFQUFFLENBQUM7UUFDL0MsT0FBTyxJQUFJLEVBQUUsQ0FBQTtJQUNmLENBQUM7SUFFRCxNQUFNLHNCQUFzQixHQUMxQixHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBZ0MsMERBQStCLENBQUMsQ0FBQTtJQUNuRixJQUFJLE1BQU0sc0JBQXNCLENBQUMsZ0JBQWdCLENBQUMsVUFBb0IsQ0FBQyxFQUFFLENBQUM7UUFDeEUsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsaURBQWlELENBQ2xELENBQUE7SUFDSCxDQUFDO0lBRUQsSUFBSSxFQUFFLENBQUE7QUFDUixDQUFDIn0=
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ipRateLimit = ipRateLimit;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
/**
|
|
6
|
+
* Creates a per-IP in-memory rate limiter middleware.
|
|
7
|
+
* Uses a simple fixed-window counter — no external dependency needed.
|
|
8
|
+
*
|
|
9
|
+
* Each path that needs limiting should get its own factory call so the
|
|
10
|
+
* counters are isolated:
|
|
11
|
+
*
|
|
12
|
+
* middlewares: [ipRateLimit({ max: 5, windowMs: 60_000 })]
|
|
13
|
+
*/
|
|
14
|
+
function ipRateLimit(options = {}) {
|
|
15
|
+
const max = options.max ?? 10;
|
|
16
|
+
const windowMs = options.windowMs ?? 60_000;
|
|
17
|
+
const buckets = new Map();
|
|
18
|
+
// Prune expired entries every 5 minutes to avoid unbounded growth.
|
|
19
|
+
const pruneInterval = setInterval(() => {
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
for (const [key, entry] of buckets) {
|
|
22
|
+
if (entry.resetAt <= now) {
|
|
23
|
+
buckets.delete(key);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}, 5 * 60_000);
|
|
27
|
+
// Allow the Node process to exit even if the interval is still active.
|
|
28
|
+
if (pruneInterval.unref) {
|
|
29
|
+
pruneInterval.unref();
|
|
30
|
+
}
|
|
31
|
+
return async function rateLimitMiddleware(req, _res, next) {
|
|
32
|
+
const ip = req.headers["x-forwarded-for"]?.split(",")[0]?.trim() ||
|
|
33
|
+
req.socket?.remoteAddress ||
|
|
34
|
+
"unknown";
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
const existing = buckets.get(ip);
|
|
37
|
+
if (!existing || existing.resetAt <= now) {
|
|
38
|
+
buckets.set(ip, { count: 1, resetAt: now + windowMs });
|
|
39
|
+
return next();
|
|
40
|
+
}
|
|
41
|
+
existing.count += 1;
|
|
42
|
+
if (existing.count > max) {
|
|
43
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "Too many requests. Please try again later.");
|
|
44
|
+
}
|
|
45
|
+
return next();
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXAtcmF0ZS1saW1pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvbWlkZGxld2FyZXMvaXAtcmF0ZS1saW1pdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQTRCQSxrQ0FrREM7QUF6RUQscURBQXVEO0FBY3ZEOzs7Ozs7OztHQVFHO0FBQ0gsU0FBZ0IsV0FBVyxDQUFDLFVBQTRCLEVBQUU7SUFDeEQsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUE7SUFDN0IsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsSUFBSSxNQUFNLENBQUE7SUFFM0MsTUFBTSxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUE7SUFFOUMsbUVBQW1FO0lBQ25FLE1BQU0sYUFBYSxHQUFHLFdBQVcsQ0FBQyxHQUFHLEVBQUU7UUFDckMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFBO1FBQ3RCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxPQUFPLEVBQUUsQ0FBQztZQUNuQyxJQUFJLEtBQUssQ0FBQyxPQUFPLElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ3pCLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7WUFDckIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFBO0lBRWQsdUVBQXVFO0lBQ3ZFLElBQUksYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3hCLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQTtJQUN2QixDQUFDO0lBRUQsT0FBTyxLQUFLLFVBQVUsbUJBQW1CLENBQ3ZDLEdBQWtCLEVBQ2xCLElBQW9CLEVBQ3BCLElBQXdCO1FBRXhCLE1BQU0sRUFBRSxHQUNMLEdBQUcsQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQVksRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFO1lBQ2pFLEdBQUcsQ0FBQyxNQUFNLEVBQUUsYUFBYTtZQUN6QixTQUFTLENBQUE7UUFFWCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7UUFDdEIsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUVoQyxJQUFJLENBQUMsUUFBUSxJQUFJLFFBQVEsQ0FBQyxPQUFPLElBQUksR0FBRyxFQUFFLENBQUM7WUFDekMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEdBQUcsUUFBUSxFQUFFLENBQUMsQ0FBQTtZQUN0RCxPQUFPLElBQUksRUFBRSxDQUFBO1FBQ2YsQ0FBQztRQUVELFFBQVEsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFBO1FBRW5CLElBQUksUUFBUSxDQUFDLEtBQUssR0FBRyxHQUFHLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsV0FBVyxFQUM3Qiw0Q0FBNEMsQ0FDN0MsQ0FBQTtRQUNILENBQUM7UUFFRCxPQUFPLElBQUksRUFBRSxDQUFBO0lBQ2YsQ0FBQyxDQUFBO0FBQ0gsQ0FBQyJ9
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateCustomerRegistration = validateCustomerRegistration;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const config_1 = require("../../config");
|
|
6
|
+
const VALID_IDENTIFIERS = ["email", "phone", "both"];
|
|
7
|
+
const EMAIL_REGEX = /^\S+@\S+\.\S+$/;
|
|
8
|
+
const PHONE_REGEX = /^\+?[0-9]{8,15}$/;
|
|
9
|
+
/**
|
|
10
|
+
* Validates registration fields on `POST /store/customers` based on the
|
|
11
|
+
* plugin's `registration.identifier` config:
|
|
12
|
+
*
|
|
13
|
+
* - "email" → email required, format checked
|
|
14
|
+
* - "phone" → phone required, format checked
|
|
15
|
+
* - "both" → email and phone both required, both format-checked
|
|
16
|
+
*
|
|
17
|
+
* Format validation applies to any field that is present, regardless of
|
|
18
|
+
* whether it was required, so bad data is always rejected early.
|
|
19
|
+
*/
|
|
20
|
+
async function validateCustomerRegistration(req, res, next) {
|
|
21
|
+
// Defensive guard — the matcher in middlewares.ts already limits to POST,
|
|
22
|
+
// but protect against accidental broader mounting.
|
|
23
|
+
if (req.method !== "POST") {
|
|
24
|
+
return next();
|
|
25
|
+
}
|
|
26
|
+
const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
|
|
27
|
+
const options = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
|
|
28
|
+
const identifier = options.registration.identifier;
|
|
29
|
+
// Fail fast if the config value is somehow outside the known set
|
|
30
|
+
if (!VALID_IDENTIFIERS.includes(identifier)) {
|
|
31
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Invalid registration identifier configuration: "${identifier}". Must be one of: ${VALID_IDENTIFIERS.join(", ")}`);
|
|
32
|
+
}
|
|
33
|
+
const { email, phone } = (req.body ?? {});
|
|
34
|
+
const emailNormalized = email?.trim() || undefined;
|
|
35
|
+
const phoneNormalized = phone?.trim() || undefined;
|
|
36
|
+
// --- Presence checks (identifier-specific) ---
|
|
37
|
+
if (identifier === "email" && !emailNormalized) {
|
|
38
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Email is required for registration");
|
|
39
|
+
}
|
|
40
|
+
if (identifier === "phone" && !phoneNormalized) {
|
|
41
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Phone is required for registration");
|
|
42
|
+
}
|
|
43
|
+
if (identifier === "both") {
|
|
44
|
+
if (!emailNormalized) {
|
|
45
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Email is required for registration");
|
|
46
|
+
}
|
|
47
|
+
if (!phoneNormalized) {
|
|
48
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Phone is required for registration");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// --- Format checks (applied to any field that is present) ---
|
|
52
|
+
if (emailNormalized && !EMAIL_REGEX.test(emailNormalized)) {
|
|
53
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid email format");
|
|
54
|
+
}
|
|
55
|
+
if (phoneNormalized && !PHONE_REGEX.test(phoneNormalized)) {
|
|
56
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid phone number format. Must be 8–15 digits, optionally prefixed with +");
|
|
57
|
+
}
|
|
58
|
+
next();
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUtY3VzdG9tZXItcmVnaXN0cmF0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2FwaS9taWRkbGV3YXJlcy92YWxpZGF0ZS1jdXN0b21lci1yZWdpc3RyYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUEyQkEsb0VBaUZDO0FBdkdELHFEQUFrRjtBQUNsRix5Q0FHcUI7QUFFckIsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxDQUFVLENBQUE7QUFFN0QsTUFBTSxXQUFXLEdBQUcsZ0JBQWdCLENBQUE7QUFDcEMsTUFBTSxXQUFXLEdBQUcsa0JBQWtCLENBQUE7QUFFdEM7Ozs7Ozs7Ozs7R0FVRztBQUNJLEtBQUssVUFBVSw0QkFBNEIsQ0FDaEQsR0FBa0IsRUFDbEIsR0FBbUIsRUFDbkIsSUFBd0I7SUFFeEIsMEVBQTBFO0lBQzFFLG1EQUFtRDtJQUNuRCxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssTUFBTSxFQUFFLENBQUM7UUFDMUIsT0FBTyxJQUFJLEVBQUUsQ0FBQTtJQUNmLENBQUM7SUFFRCxNQUFNLFlBQVksR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FDcEMsaUNBQXlCLENBQUMsYUFBYSxDQUN4QyxDQUFBO0lBQ0QsTUFBTSxPQUFPLEdBQUcsSUFBQSwyQ0FBa0MsRUFBQyxZQUFZLENBQUMsQ0FBQTtJQUNoRSxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQTtJQUVsRCxpRUFBaUU7SUFDakUsSUFBSSxDQUFFLGlCQUF1QyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQ25FLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG1EQUFtRCxVQUFVLHNCQUFzQixpQkFBaUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDbEgsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLENBR3ZDLENBQUE7SUFFRCxNQUFNLGVBQWUsR0FBRyxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksU0FBUyxDQUFBO0lBQ2xELE1BQU0sZUFBZSxHQUFHLEtBQUssRUFBRSxJQUFJLEVBQUUsSUFBSSxTQUFTLENBQUE7SUFFbEQsZ0RBQWdEO0lBRWhELElBQUksVUFBVSxLQUFLLE9BQU8sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQy9DLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG9DQUFvQyxDQUNyQyxDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksVUFBVSxLQUFLLE9BQU8sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQy9DLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG9DQUFvQyxDQUNyQyxDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksVUFBVSxLQUFLLE1BQU0sRUFBRSxDQUFDO1FBQzFCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNyQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixvQ0FBb0MsQ0FDckMsQ0FBQTtRQUNILENBQUM7UUFDRCxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDckIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsb0NBQW9DLENBQ3JDLENBQUE7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELCtEQUErRDtJQUUvRCxJQUFJLGVBQWUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUMxRCxNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixzQkFBc0IsQ0FDdkIsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLGVBQWUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUMxRCxNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw4RUFBOEUsQ0FDL0UsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLEVBQUUsQ0FBQTtBQUNSLENBQUMifQ==
|