@lodashventure/medusa-login-provider 0.0.7 → 0.0.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/.medusa/server/medusa-config-auth.example.js +58 -0
- package/.medusa/server/src/api/store/line-pending-customers/route.js +222 -0
- package/.medusa/server/src/index.js +31 -0
- package/.medusa/server/src/providers/line/customer-helper.js +152 -0
- package/.medusa/server/src/providers/line/index.js +3 -2
- package/.medusa/server/src/providers/line/redis-helper.js +132 -0
- package/.medusa/server/src/providers/line/service.js +197 -53
- package/.medusa/server/src/providers/line/types.js +3 -0
- package/.medusa/server/src/providers/line/utils.js +119 -0
- package/package.json +26 -3
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
4
|
+
/**
|
|
5
|
+
* Example Medusa configuration with LINE auth provider
|
|
6
|
+
*
|
|
7
|
+
* Add this auth module configuration to your medusa-config.ts
|
|
8
|
+
*/
|
|
9
|
+
exports.default = (0, utils_1.defineConfig)({
|
|
10
|
+
projectConfig: {
|
|
11
|
+
// ... your existing project config
|
|
12
|
+
databaseUrl: process.env.MEDUSA_DATABASE_URL,
|
|
13
|
+
http: {
|
|
14
|
+
storeCors: process.env.MEDUSA_STORE_CORS,
|
|
15
|
+
adminCors: process.env.MEDUSA_ADMIN_CORS,
|
|
16
|
+
authCors: process.env.MEDUSA_AUTH_CORS,
|
|
17
|
+
jwtSecret: process.env.MEDUSA_JWT_SECRET || "supersecret",
|
|
18
|
+
cookieSecret: process.env.MEDUSA_COOKIE_SECRET || "supersecret",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
plugins: [
|
|
22
|
+
// Remove the LINE provider from plugins section if it's there
|
|
23
|
+
// ... other plugins
|
|
24
|
+
],
|
|
25
|
+
modules: [
|
|
26
|
+
// ... other modules
|
|
27
|
+
{
|
|
28
|
+
resolve: "@medusajs/medusa/auth",
|
|
29
|
+
options: {
|
|
30
|
+
providers: [
|
|
31
|
+
// Keep existing providers like emailpass
|
|
32
|
+
{
|
|
33
|
+
resolve: "@medusajs/medusa/auth-emailpass",
|
|
34
|
+
id: "emailpass",
|
|
35
|
+
options: {
|
|
36
|
+
// emailpass options
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
// Add LINE provider here
|
|
40
|
+
{
|
|
41
|
+
resolve: "@lodashventure/medusa-login-provider/providers/line",
|
|
42
|
+
id: "line",
|
|
43
|
+
options: {
|
|
44
|
+
lineChannelId: process.env.LINE_CHANNEL_ID,
|
|
45
|
+
lineChannelSecret: process.env.LINE_CHANNEL_SECRET,
|
|
46
|
+
// Optional: specify callback URL if different from default
|
|
47
|
+
callbackUrl: process.env.LINE_CALLBACK_URL,
|
|
48
|
+
// Optional: auto-create customers
|
|
49
|
+
autoCreateCustomer: true,
|
|
50
|
+
syncProfileData: true,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVkdXNhLWNvbmZpZy1hdXRoLmV4YW1wbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9tZWR1c2EtY29uZmlnLWF1dGguZXhhbXBsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHFEQUFrRTtBQUVsRTs7OztHQUlHO0FBQ0gsa0JBQWUsSUFBQSxvQkFBWSxFQUFDO0lBQzFCLGFBQWEsRUFBRTtRQUNiLG1DQUFtQztRQUNuQyxXQUFXLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUI7UUFDNUMsSUFBSSxFQUFFO1lBQ0osU0FBUyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWtCO1lBQ3pDLFNBQVMsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFrQjtZQUN6QyxRQUFRLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBaUI7WUFDdkMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLElBQUksYUFBYTtZQUN6RCxZQUFZLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsSUFBSSxhQUFhO1NBQ2hFO0tBQ0Y7SUFDRCxPQUFPLEVBQUU7SUFDUCw4REFBOEQ7SUFDOUQsb0JBQW9CO0tBQ3JCO0lBQ0QsT0FBTyxFQUFFO1FBQ1Asb0JBQW9CO1FBQ3BCO1lBQ0UsT0FBTyxFQUFFLHVCQUF1QjtZQUNoQyxPQUFPLEVBQUU7Z0JBQ1AsU0FBUyxFQUFFO29CQUNULHlDQUF5QztvQkFDekM7d0JBQ0UsT0FBTyxFQUFFLGlDQUFpQzt3QkFDMUMsRUFBRSxFQUFFLFdBQVc7d0JBQ2YsT0FBTyxFQUFFO3dCQUNQLG9CQUFvQjt5QkFDckI7cUJBQ0Y7b0JBQ0QseUJBQXlCO29CQUN6Qjt3QkFDRSxPQUFPLEVBQUUscURBQXFEO3dCQUM5RCxFQUFFLEVBQUUsTUFBTTt3QkFDVixPQUFPLEVBQUU7NEJBQ1AsYUFBYSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZTs0QkFDMUMsaUJBQWlCLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUI7NEJBQ2xELDJEQUEyRDs0QkFDM0QsV0FBVyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCOzRCQUMxQyxrQ0FBa0M7NEJBQ2xDLGtCQUFrQixFQUFFLElBQUk7NEJBQ3hCLGVBQWUsRUFBRSxJQUFJO3lCQUN0QjtxQkFDRjtpQkFDRjthQUNGO1NBQ0Y7S0FDRjtDQUNGLENBQUMsQ0FBQyJ9
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.POST = POST;
|
|
7
|
+
exports.GET = GET;
|
|
8
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
9
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
10
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
11
|
+
const line_create_customer_1 = require("../../../workflows/line-create-customer");
|
|
12
|
+
/**
|
|
13
|
+
* POST /store/line-pending-customers
|
|
14
|
+
* Creates a customer from pending LINE data stored in Redis
|
|
15
|
+
* Requires JWT with auth_identity_id
|
|
16
|
+
*/
|
|
17
|
+
async function POST(req, res) {
|
|
18
|
+
const logger = req.scope.resolve(utils_1.ContainerRegistrationKeys.LOGGER);
|
|
19
|
+
const customerService = req.scope.resolve(utils_1.Modules.CUSTOMER);
|
|
20
|
+
// Extract JWT from Authorization header
|
|
21
|
+
const authHeader = req.headers.authorization;
|
|
22
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
23
|
+
return res.status(401).json({
|
|
24
|
+
success: false,
|
|
25
|
+
error: "Authorization header with Bearer token is required"
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const token = authHeader.substring(7);
|
|
29
|
+
let auth_identity_id;
|
|
30
|
+
try {
|
|
31
|
+
// Decode JWT to get auth_identity_id (no verification, just decode)
|
|
32
|
+
const decoded = jsonwebtoken_1.default.decode(token);
|
|
33
|
+
if (!decoded || !decoded.auth_identity_id) {
|
|
34
|
+
return res.status(401).json({
|
|
35
|
+
success: false,
|
|
36
|
+
error: "Invalid token: auth_identity_id not found"
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
auth_identity_id = decoded.auth_identity_id;
|
|
40
|
+
logger.info(`Extracted auth_identity_id from JWT: ${auth_identity_id}`);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
logger.error("Error decoding JWT:", error);
|
|
44
|
+
return res.status(401).json({
|
|
45
|
+
success: false,
|
|
46
|
+
error: "Invalid token"
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Get Redis URL from environment
|
|
50
|
+
const redisUrl = process.env.MEDUSA_REDIS_URL || process.env.REDIS_URL;
|
|
51
|
+
if (!redisUrl) {
|
|
52
|
+
return res.status(503).json({
|
|
53
|
+
success: false,
|
|
54
|
+
error: "Redis is not configured"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const redis = new ioredis_1.default(redisUrl);
|
|
58
|
+
const key = `line:pending_customer:${auth_identity_id}`;
|
|
59
|
+
try {
|
|
60
|
+
// Step 1: Retrieve pending customer data from Redis using auth_identity_id
|
|
61
|
+
const pendingDataStr = await redis.get(key);
|
|
62
|
+
if (!pendingDataStr) {
|
|
63
|
+
logger.warn(`No pending customer data found for auth_identity_id: ${auth_identity_id}`);
|
|
64
|
+
return res.status(404).json({
|
|
65
|
+
success: false,
|
|
66
|
+
error: "No pending customer data found for this auth_identity_id"
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const pendingData = JSON.parse(pendingDataStr);
|
|
70
|
+
logger.info(`Retrieved pending customer data for LINE user: ${pendingData.line_user_id}`);
|
|
71
|
+
// Step 2: Check if customer already exists with this email
|
|
72
|
+
if (pendingData.email) {
|
|
73
|
+
const existingCustomers = await customerService.listCustomers({
|
|
74
|
+
email: pendingData.email
|
|
75
|
+
});
|
|
76
|
+
if (existingCustomers?.length > 0) {
|
|
77
|
+
// Update existing customer with LINE data
|
|
78
|
+
const customer = existingCustomers[0];
|
|
79
|
+
const updated = await customerService.updateCustomers(customer.id, {
|
|
80
|
+
metadata: {
|
|
81
|
+
...customer.metadata,
|
|
82
|
+
line_user_id: pendingData.line_user_id,
|
|
83
|
+
line_display_name: pendingData.display_name,
|
|
84
|
+
line_picture_url: pendingData.picture_url,
|
|
85
|
+
line_status_message: pendingData.status_message,
|
|
86
|
+
line_linked_at: new Date().toISOString(),
|
|
87
|
+
auth_identity_id: auth_identity_id
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// Step 3: Update auth identity with customer ID
|
|
91
|
+
const authService = req.scope.resolve(utils_1.Modules.AUTH);
|
|
92
|
+
await authService.updateAuthIdentities({
|
|
93
|
+
id: auth_identity_id,
|
|
94
|
+
app_metadata: {
|
|
95
|
+
customer_id: customer.id
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
// Step 4: Delete from Redis after successful creation
|
|
99
|
+
await redis.del(key);
|
|
100
|
+
logger.info(`Linked existing customer ${customer.id} with LINE user ${pendingData.line_user_id}`);
|
|
101
|
+
return res.json({
|
|
102
|
+
success: true,
|
|
103
|
+
customer: updated,
|
|
104
|
+
message: "Existing customer linked with LINE account",
|
|
105
|
+
action: "linked"
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Step 3: Create new customer using workflow
|
|
110
|
+
logger.info(`Creating new customer for LINE user: ${pendingData.line_user_id}`);
|
|
111
|
+
const { result } = await (0, line_create_customer_1.lineCreateCustomerWorkflow)(req.scope).run({
|
|
112
|
+
input: {
|
|
113
|
+
data: {
|
|
114
|
+
email: pendingData.email || `line_${pendingData.line_user_id}@line.me`,
|
|
115
|
+
line_user_id: pendingData.line_user_id,
|
|
116
|
+
display_name: pendingData.display_name,
|
|
117
|
+
picture_url: pendingData.picture_url,
|
|
118
|
+
name: pendingData.name,
|
|
119
|
+
auth_identity_id: auth_identity_id
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// Step 4: Update auth identity with customer ID
|
|
124
|
+
const authService = req.scope.resolve(utils_1.Modules.AUTH);
|
|
125
|
+
await authService.updateAuthIdentities({
|
|
126
|
+
id: auth_identity_id,
|
|
127
|
+
app_metadata: {
|
|
128
|
+
customer_id: result.customer.id
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
// Step 5: Delete from Redis after successful creation
|
|
132
|
+
await redis.del(key);
|
|
133
|
+
logger.info(`Created customer ${result.customer.id} from pending LINE data for auth_identity ${auth_identity_id}`);
|
|
134
|
+
return res.status(201).json({
|
|
135
|
+
success: true,
|
|
136
|
+
customer: result.customer,
|
|
137
|
+
message: "Customer created successfully from LINE data",
|
|
138
|
+
action: "created"
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
logger.error("Error creating customer from pending LINE data:", error);
|
|
143
|
+
return res.status(500).json({
|
|
144
|
+
success: false,
|
|
145
|
+
error: error.message || "Failed to create customer"
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
await redis.quit();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* GET /store/line-pending-customers
|
|
154
|
+
* Checks if pending customer data exists for the auth_identity_id in JWT
|
|
155
|
+
*/
|
|
156
|
+
async function GET(req, res) {
|
|
157
|
+
const logger = req.scope.resolve(utils_1.ContainerRegistrationKeys.LOGGER);
|
|
158
|
+
// Extract JWT from Authorization header
|
|
159
|
+
const authHeader = req.headers.authorization;
|
|
160
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
161
|
+
return res.status(401).json({
|
|
162
|
+
success: false,
|
|
163
|
+
error: "Authorization header with Bearer token is required"
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
const token = authHeader.substring(7);
|
|
167
|
+
let auth_identity_id;
|
|
168
|
+
try {
|
|
169
|
+
// Decode JWT to get auth_identity_id
|
|
170
|
+
const decoded = jsonwebtoken_1.default.decode(token);
|
|
171
|
+
if (!decoded || !decoded.auth_identity_id) {
|
|
172
|
+
return res.status(401).json({
|
|
173
|
+
success: false,
|
|
174
|
+
error: "Invalid token: auth_identity_id not found"
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
auth_identity_id = decoded.auth_identity_id;
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
logger.error("Error decoding JWT:", error);
|
|
181
|
+
return res.status(401).json({
|
|
182
|
+
success: false,
|
|
183
|
+
error: "Invalid token"
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
const redisUrl = process.env.MEDUSA_REDIS_URL || process.env.REDIS_URL;
|
|
187
|
+
if (!redisUrl) {
|
|
188
|
+
return res.status(503).json({
|
|
189
|
+
success: false,
|
|
190
|
+
error: "Redis is not configured"
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const redis = new ioredis_1.default(redisUrl);
|
|
194
|
+
const key = `line:pending_customer:${auth_identity_id}`;
|
|
195
|
+
try {
|
|
196
|
+
const pendingDataStr = await redis.get(key);
|
|
197
|
+
if (!pendingDataStr) {
|
|
198
|
+
return res.json({
|
|
199
|
+
success: true,
|
|
200
|
+
has_pending_data: false,
|
|
201
|
+
message: "No pending customer data found"
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
const pendingData = JSON.parse(pendingDataStr);
|
|
205
|
+
return res.json({
|
|
206
|
+
success: true,
|
|
207
|
+
has_pending_data: true,
|
|
208
|
+
pending_customer: pendingData
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
logger.error("Error retrieving pending customer data:", error);
|
|
213
|
+
return res.status(500).json({
|
|
214
|
+
success: false,
|
|
215
|
+
error: "Failed to retrieve pending customer data"
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
await redis.quit();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2xpbmUtcGVuZGluZy1jdXN0b21lcnMvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUE0QkEsb0JBOEpDO0FBTUQsa0JBOEVDO0FBN1FELHFEQUE4RTtBQUM5RSxzREFBMkI7QUFDM0IsZ0VBQThCO0FBQzlCLGtGQUFvRjtBQW1CcEY7Ozs7R0FJRztBQUNJLEtBQUssVUFBVSxJQUFJLENBQ3hCLEdBQWtCLEVBQ2xCLEdBQW1CO0lBRW5CLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQ2xFLE1BQU0sZUFBZSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQTtJQUUzRCx3Q0FBd0M7SUFDeEMsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUE7SUFDNUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUNyRCxPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQzFCLE9BQU8sRUFBRSxLQUFLO1lBQ2QsS0FBSyxFQUFFLG9EQUFvRDtTQUM1RCxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUNyQyxJQUFJLGdCQUF3QixDQUFBO0lBRTVCLElBQUksQ0FBQztRQUNILG9FQUFvRTtRQUNwRSxNQUFNLE9BQU8sR0FBRyxzQkFBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQWUsQ0FBQTtRQUUvQyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsT0FB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
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.LineProvider = void 0;
|
|
21
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
22
|
+
const service_1 = __importDefault(require("./providers/line/service"));
|
|
23
|
+
exports.default = (0, utils_1.ModuleProvider)(utils_1.Modules.AUTH, {
|
|
24
|
+
services: [service_1.default],
|
|
25
|
+
});
|
|
26
|
+
// Export the LINE provider for direct access
|
|
27
|
+
var service_2 = require("./providers/line/service");
|
|
28
|
+
Object.defineProperty(exports, "LineProvider", { enumerable: true, get: function () { return __importDefault(service_2).default; } });
|
|
29
|
+
__exportStar(require("./providers/line/customer-helper"), exports);
|
|
30
|
+
__exportStar(require("./providers/line/utils"), exports);
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxxREFBb0U7QUFDcEUsdUVBQTJEO0FBRTNELGtCQUFlLElBQUEsc0JBQWMsRUFBQyxlQUFPLENBQUMsSUFBSSxFQUFFO0lBQzFDLFFBQVEsRUFBRSxDQUFDLGlCQUFtQixDQUFDO0NBQ2hDLENBQUMsQ0FBQztBQUVILDZDQUE2QztBQUM3QyxvREFBbUU7QUFBMUQsd0hBQUEsT0FBTyxPQUFnQjtBQUNoQyxtRUFBaUQ7QUFDakQseURBQXVDIn0=
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createOrUpdateLineCustomer = createOrUpdateLineCustomer;
|
|
4
|
+
exports.extractCustomerData = extractCustomerData;
|
|
5
|
+
exports.shouldCreateCustomer = shouldCreateCustomer;
|
|
6
|
+
const core_flows_1 = require("@medusajs/medusa/core-flows");
|
|
7
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
8
|
+
/**
|
|
9
|
+
* Creates or updates a customer account for a LINE authenticated user
|
|
10
|
+
* Uses Medusa's createCustomerAccountWorkflow for proper integration
|
|
11
|
+
*/
|
|
12
|
+
async function createOrUpdateLineCustomer(options) {
|
|
13
|
+
const { authIdentityId, userMetadata, container, logger } = options;
|
|
14
|
+
const customerService = container.resolve(utils_1.Modules.CUSTOMER);
|
|
15
|
+
const authService = container.resolve(utils_1.Modules.AUTH);
|
|
16
|
+
const email = userMetadata.email || `line_${userMetadata.line_user_id}@line.me`;
|
|
17
|
+
const firstName = userMetadata.first_name || userMetadata.display_name || "LINE User";
|
|
18
|
+
const lastName = userMetadata.last_name || "";
|
|
19
|
+
try {
|
|
20
|
+
// Check if customer already exists
|
|
21
|
+
const existingCustomers = await customerService.listCustomers({ email });
|
|
22
|
+
if (existingCustomers?.length > 0) {
|
|
23
|
+
// Update existing customer
|
|
24
|
+
const customer = existingCustomers[0];
|
|
25
|
+
await customerService.updateCustomers(customer.id, {
|
|
26
|
+
first_name: firstName,
|
|
27
|
+
last_name: lastName,
|
|
28
|
+
metadata: {
|
|
29
|
+
...customer.metadata,
|
|
30
|
+
line_user_id: userMetadata.line_user_id,
|
|
31
|
+
line_display_name: userMetadata.display_name,
|
|
32
|
+
line_picture_url: userMetadata.picture_url,
|
|
33
|
+
line_status_message: userMetadata.status_message,
|
|
34
|
+
line_updated_at: new Date().toISOString(),
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
// Update auth identity with customer ID
|
|
38
|
+
await authService.updateAuthIdentities({
|
|
39
|
+
id: authIdentityId,
|
|
40
|
+
app_metadata: {
|
|
41
|
+
customer_id: customer.id,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
if (logger) {
|
|
45
|
+
logger.info(`Updated existing customer ${customer.id} for LINE user ${userMetadata.line_user_id}`);
|
|
46
|
+
}
|
|
47
|
+
return { customer, created: false };
|
|
48
|
+
}
|
|
49
|
+
// Create new customer using workflow
|
|
50
|
+
const { result } = await (0, core_flows_1.createCustomerAccountWorkflow)(container).run({
|
|
51
|
+
input: {
|
|
52
|
+
authIdentityId,
|
|
53
|
+
customerData: {
|
|
54
|
+
email,
|
|
55
|
+
first_name: firstName,
|
|
56
|
+
last_name: lastName,
|
|
57
|
+
metadata: {
|
|
58
|
+
line_user_id: userMetadata.line_user_id,
|
|
59
|
+
line_display_name: userMetadata.display_name,
|
|
60
|
+
line_picture_url: userMetadata.picture_url,
|
|
61
|
+
line_status_message: userMetadata.status_message,
|
|
62
|
+
line_created_at: new Date().toISOString(),
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
if (logger) {
|
|
68
|
+
logger.info(`Created new customer ${result.id} for LINE user ${userMetadata.line_user_id}`);
|
|
69
|
+
}
|
|
70
|
+
return { customer: result, created: true };
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (logger) {
|
|
74
|
+
logger.error(`Failed to create/update customer for LINE user ${userMetadata.line_user_id}:`, error);
|
|
75
|
+
}
|
|
76
|
+
// Fallback: Try direct customer creation
|
|
77
|
+
try {
|
|
78
|
+
const customer = await customerService.createCustomers({
|
|
79
|
+
email,
|
|
80
|
+
first_name: firstName,
|
|
81
|
+
last_name: lastName,
|
|
82
|
+
metadata: {
|
|
83
|
+
line_user_id: userMetadata.line_user_id,
|
|
84
|
+
line_display_name: userMetadata.display_name,
|
|
85
|
+
line_picture_url: userMetadata.picture_url,
|
|
86
|
+
line_status_message: userMetadata.status_message,
|
|
87
|
+
line_created_at: new Date().toISOString(),
|
|
88
|
+
auth_identity_id: authIdentityId,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
// Update auth identity with customer ID
|
|
92
|
+
await authService.updateAuthIdentities({
|
|
93
|
+
id: authIdentityId,
|
|
94
|
+
app_metadata: {
|
|
95
|
+
customer_id: customer.id,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
if (logger) {
|
|
99
|
+
logger.info(`Created customer ${customer.id} via fallback method for LINE user ${userMetadata.line_user_id}`);
|
|
100
|
+
}
|
|
101
|
+
return { customer, created: true };
|
|
102
|
+
}
|
|
103
|
+
catch (fallbackError) {
|
|
104
|
+
if (logger) {
|
|
105
|
+
logger.error(`Fallback customer creation also failed:`, fallbackError);
|
|
106
|
+
}
|
|
107
|
+
throw fallbackError;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Extract customer data from LINE user metadata
|
|
113
|
+
*/
|
|
114
|
+
function extractCustomerData(userMetadata) {
|
|
115
|
+
const email = userMetadata.email || `line_${userMetadata.line_user_id}@line.me`;
|
|
116
|
+
const displayName = userMetadata.name || userMetadata.display_name || "";
|
|
117
|
+
const nameParts = displayName.trim().split(" ");
|
|
118
|
+
return {
|
|
119
|
+
email,
|
|
120
|
+
first_name: userMetadata.first_name || nameParts[0] || "LINE User",
|
|
121
|
+
last_name: userMetadata.last_name || nameParts.slice(1).join(" ") || "",
|
|
122
|
+
metadata: {
|
|
123
|
+
line_user_id: userMetadata.line_user_id,
|
|
124
|
+
line_display_name: userMetadata.display_name,
|
|
125
|
+
line_picture_url: userMetadata.picture_url || userMetadata.picture,
|
|
126
|
+
line_status_message: userMetadata.status_message,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Check if a customer needs to be created based on auth identity
|
|
132
|
+
*/
|
|
133
|
+
async function shouldCreateCustomer(authIdentity, container) {
|
|
134
|
+
// Check if customer creation flag is set
|
|
135
|
+
if (!authIdentity.user_metadata?.needs_customer_creation) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
// Check if customer already exists in app_metadata
|
|
139
|
+
if (authIdentity.app_metadata?.customer_id) {
|
|
140
|
+
const customerService = container.resolve(utils_1.Modules.CUSTOMER);
|
|
141
|
+
try {
|
|
142
|
+
await customerService.retrieveCustomer(authIdentity.app_metadata.customer_id);
|
|
143
|
+
return false; // Customer exists
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Customer doesn't exist, should create
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tZXItaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3Byb3ZpZGVycy9saW5lL2N1c3RvbWVyLWhlbHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQTJCQSxnRUFnSEM7QUFLRCxrREFnQkM7QUFLRCxvREFzQkM7QUEzTEQsNERBQTRFO0FBRTVFLHFEQUFvRDtBQXFCcEQ7OztHQUdHO0FBQ0ksS0FBSyxVQUFVLDBCQUEwQixDQUM5QyxPQUFrQztJQUVsQyxNQUFNLEVBQUUsY0FBYyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDO0lBQ3BFLE1BQU0sZUFBZSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzVELE1BQU0sV0FBVyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRXBELE1BQU0sS0FBSyxHQUFHLFlBQVksQ0FBQyxLQUFLLElBQUksUUFBUSxZQUFZLENBQUMsWUFBWSxVQUFVLENBQUM7SUFDaEYsTUFBTSxTQUFTLEdBQUcsWUFBWSxDQUFDLFVBQVUsSUFBSSxZQUFZLENBQUMsWUFBWSxJQUFJLFdBQVcsQ0FBQztJQUN0RixNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsU0FBUyxJQUFJLEVBQUUsQ0FBQztJQUU5QyxJQUFJLENBQUM7UUFDSCxtQ0FBbUM7UUFDbkMsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLGVBQWUsQ0FBQyxhQUFhLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBRXpFLElBQUksaUJBQWlCLEVBQUUsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2xDLDJCQUEyQjtZQUMzQixNQUFNLFFBQVEsR0FBRyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUV0QyxNQUFNLGVBQWUsQ0FBQyxlQUFlLENBQUMsUUFB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
|
|
@@ -5,7 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const utils_1 = require("@medusajs/framework/utils");
|
|
7
7
|
const service_1 = __importDefault(require("./service"));
|
|
8
|
+
const services = [service_1.default];
|
|
8
9
|
exports.default = (0, utils_1.ModuleProvider)(utils_1.Modules.AUTH, {
|
|
9
|
-
services
|
|
10
|
+
services,
|
|
10
11
|
});
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL2xpbmUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxxREFBb0U7QUFDcEUsd0RBQTRDO0FBRTVDLE1BQU0sUUFBUSxHQUFHLENBQUMsaUJBQW1CLENBQUMsQ0FBQztBQUV2QyxrQkFBZSxJQUFBLHNCQUFjLEVBQUMsZUFBTyxDQUFDLElBQUksRUFBRTtJQUMxQyxRQUFRO0NBQ1QsQ0FBQyxDQUFDIn0=
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LineRedisHelper = void 0;
|
|
7
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
8
|
+
class LineRedisHelper {
|
|
9
|
+
constructor(redisUrl, logger) {
|
|
10
|
+
this.PREFIX = "line:pending_customer:";
|
|
11
|
+
this.TTL_SECONDS = 86400; // 24 hours
|
|
12
|
+
this.redis = new ioredis_1.default(redisUrl);
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Store pending customer data in Redis with TTL
|
|
17
|
+
* Uses auth_identity_id as the key for easy retrieval
|
|
18
|
+
*/
|
|
19
|
+
async storePendingCustomer(authIdentityId, data) {
|
|
20
|
+
const key = `${this.PREFIX}${authIdentityId}`;
|
|
21
|
+
const pendingData = {
|
|
22
|
+
...data,
|
|
23
|
+
created_at: new Date().toISOString(),
|
|
24
|
+
expires_at: new Date(Date.now() + this.TTL_SECONDS * 1000).toISOString(),
|
|
25
|
+
};
|
|
26
|
+
try {
|
|
27
|
+
await this.redis.setex(key, this.TTL_SECONDS, JSON.stringify(pendingData));
|
|
28
|
+
this.logger.info(`Stored pending customer in Redis: ${key}`);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
this.logger.error(`Failed to store pending customer in Redis: ${error}`);
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Retrieve pending customer data from Redis by auth_identity_id
|
|
37
|
+
*/
|
|
38
|
+
async getPendingCustomer(authIdentityId) {
|
|
39
|
+
const key = `${this.PREFIX}${authIdentityId}`;
|
|
40
|
+
try {
|
|
41
|
+
const data = await this.redis.get(key);
|
|
42
|
+
if (!data) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return JSON.parse(data);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
this.logger.error(`Failed to get pending customer from Redis: ${error}`);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Delete pending customer data from Redis (after successful creation)
|
|
54
|
+
*/
|
|
55
|
+
async deletePendingCustomer(authIdentityId) {
|
|
56
|
+
const key = `${this.PREFIX}${authIdentityId}`;
|
|
57
|
+
try {
|
|
58
|
+
await this.redis.del(key);
|
|
59
|
+
this.logger.info(`Deleted pending customer from Redis: ${key}`);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
this.logger.error(`Failed to delete pending customer from Redis: ${error}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get all pending customers (for admin monitoring)
|
|
67
|
+
*/
|
|
68
|
+
async getAllPendingCustomers() {
|
|
69
|
+
try {
|
|
70
|
+
const pattern = `${this.PREFIX}*`;
|
|
71
|
+
const keys = await this.redis.keys(pattern);
|
|
72
|
+
if (keys.length === 0) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
const pipeline = this.redis.pipeline();
|
|
76
|
+
keys.forEach(key => pipeline.get(key));
|
|
77
|
+
const results = await pipeline.exec();
|
|
78
|
+
const pendingCustomers = [];
|
|
79
|
+
results?.forEach(([err, data]) => {
|
|
80
|
+
if (!err && data) {
|
|
81
|
+
try {
|
|
82
|
+
pendingCustomers.push(JSON.parse(data));
|
|
83
|
+
}
|
|
84
|
+
catch (parseError) {
|
|
85
|
+
this.logger.error(`Failed to parse pending customer data: ${parseError}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return pendingCustomers;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
this.logger.error(`Failed to get all pending customers from Redis: ${error}`);
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Check if customer data exists in Redis
|
|
98
|
+
*/
|
|
99
|
+
async hasPendingCustomer(authIdentityId) {
|
|
100
|
+
const key = `${this.PREFIX}${authIdentityId}`;
|
|
101
|
+
try {
|
|
102
|
+
const exists = await this.redis.exists(key);
|
|
103
|
+
return exists === 1;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
this.logger.error(`Failed to check pending customer in Redis: ${error}`);
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Update TTL for pending customer
|
|
112
|
+
*/
|
|
113
|
+
async extendTTL(authIdentityId, additionalSeconds = 86400) {
|
|
114
|
+
const key = `${this.PREFIX}${authIdentityId}`;
|
|
115
|
+
try {
|
|
116
|
+
const result = await this.redis.expire(key, this.TTL_SECONDS + additionalSeconds);
|
|
117
|
+
return result === 1;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
this.logger.error(`Failed to extend TTL for pending customer: ${error}`);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Close Redis connection
|
|
126
|
+
*/
|
|
127
|
+
async disconnect() {
|
|
128
|
+
await this.redis.quit();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
exports.LineRedisHelper = LineRedisHelper;
|
|
132
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkaXMtaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3Byb3ZpZGVycy9saW5lL3JlZGlzLWhlbHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxzREFBMkI7QUFlM0IsTUFBYSxlQUFlO0lBTTFCLFlBQVksUUFBZ0IsRUFBRSxNQUFjO1FBSDNCLFdBQU0sR0FBRyx3QkFBd0IsQ0FBQTtRQUNqQyxnQkFBVyxHQUFHLEtBQUssQ0FBQSxDQUFDLFdBQVc7UUFHOUMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLGlCQUFLLENBQUMsUUFBUSxDQUFDLENBQUE7UUFDaEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUE7SUFDdEIsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxvQkFBb0IsQ0FDeEIsY0FBc0IsRUFDdEIsSUFBNEQ7UUFFNUQsTUFBTSxHQUFHLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFHLGNBQWMsRUFBRSxDQUFBO1FBQzdDLE1BQU0sV0FBVyxHQUF3QjtZQUN2QyxHQUFHLElBQUk7WUFDUCxVQUFVLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUU7WUFDcEMsVUFBVSxFQUFFLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRTtTQUN6RSxDQUFBO1FBRUQsSUFBSSxDQUFDO1lBQ0gsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FDcEIsR0FBRyxFQUNILElBQUksQ0FBQyxXQUFXLEVBQ2hCLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLENBQzVCLENBQUE7WUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxxQ0FBcUMsR0FBRyxFQUFFLENBQUMsQ0FBQTtRQUM5RCxDQUFDO1FBQUMsT0FBTyxLQUFL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
|
|
@@ -6,11 +6,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const utils_1 = require("@medusajs/framework/utils");
|
|
7
7
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
8
|
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const redis_helper_1 = require("./redis-helper");
|
|
9
10
|
class LineProviderService extends utils_1.AbstractAuthModuleProvider {
|
|
10
|
-
constructor(
|
|
11
|
+
constructor(dependencies, options) {
|
|
11
12
|
super();
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
13
|
+
this.LINE_TOKEN_ENDPOINT = "https://api.line.me/oauth2/v2.1/token";
|
|
14
|
+
this.LINE_PROFILE_ENDPOINT = "https://api.line.me/v2/profile";
|
|
15
|
+
this.logger_ = dependencies.logger;
|
|
16
|
+
this.options_ = {
|
|
17
|
+
autoCreateCustomer: true,
|
|
18
|
+
syncProfileData: true,
|
|
19
|
+
storeUnlinkedInRedis: true,
|
|
20
|
+
...options,
|
|
21
|
+
};
|
|
22
|
+
// Initialize Redis helper if Redis URL is provided
|
|
23
|
+
if (this.options_.redisUrl && this.options_.storeUnlinkedInRedis) {
|
|
24
|
+
this.redisHelper = new redis_helper_1.LineRedisHelper(this.options_.redisUrl, this.logger_);
|
|
25
|
+
}
|
|
14
26
|
}
|
|
15
27
|
static validateOptions(options) {
|
|
16
28
|
if (!options.lineChannelId) {
|
|
@@ -19,11 +31,8 @@ class LineProviderService extends utils_1.AbstractAuthModuleProvider {
|
|
|
19
31
|
if (!options.lineChannelSecret) {
|
|
20
32
|
throw new Error("line channel secret is required");
|
|
21
33
|
}
|
|
22
|
-
if (!options.lineChannelId) {
|
|
23
|
-
throw new Error("redirect url is required");
|
|
24
|
-
}
|
|
25
34
|
}
|
|
26
|
-
async register(
|
|
35
|
+
async register(_data, _authIdentityService) {
|
|
27
36
|
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "Line does not support registration. Use method `authenticate` instead.");
|
|
28
37
|
}
|
|
29
38
|
async authenticate(data, authIdentityService) {
|
|
@@ -36,16 +45,19 @@ class LineProviderService extends utils_1.AbstractAuthModuleProvider {
|
|
|
36
45
|
};
|
|
37
46
|
}
|
|
38
47
|
const stateKey = crypto_1.default.randomBytes(32).toString("hex");
|
|
48
|
+
// Use Medusa's native callback URL pattern
|
|
49
|
+
const baseUrl = body?.callback_url;
|
|
39
50
|
const state = {
|
|
40
|
-
callback_url:
|
|
51
|
+
callback_url: baseUrl,
|
|
41
52
|
};
|
|
42
53
|
await authIdentityService.setState(stateKey, state);
|
|
43
|
-
return this.getRedirect(this.options_.lineChannelId,
|
|
54
|
+
return this.getRedirect(this.options_.lineChannelId, baseUrl, stateKey);
|
|
44
55
|
}
|
|
45
56
|
async validateCallback(req, authIdentityService) {
|
|
46
57
|
const query = req.query ?? {};
|
|
47
58
|
const body = req.body ?? {};
|
|
48
59
|
if (query.error) {
|
|
60
|
+
this.logger_.error(`LINE OAuth error: ${query.error} - ${query.error_description} - ${query.error_uri} - state: ${query.state}`);
|
|
49
61
|
return {
|
|
50
62
|
success: false,
|
|
51
63
|
error: `${query.error_description}, read more at: ${query.error_uri}`,
|
|
@@ -53,88 +65,220 @@ class LineProviderService extends utils_1.AbstractAuthModuleProvider {
|
|
|
53
65
|
}
|
|
54
66
|
const code = query?.code ?? body?.code;
|
|
55
67
|
if (!code) {
|
|
56
|
-
|
|
68
|
+
this.logger_.error(`LINE callback validation failed: No authorization code provided - query: ${JSON.stringify(query)} - body: ${JSON.stringify(body)}`);
|
|
69
|
+
return { success: false, error: "No authorization code provided" };
|
|
57
70
|
}
|
|
58
|
-
const
|
|
71
|
+
const stateKey = query?.state ?? body?.state;
|
|
72
|
+
if (!stateKey) {
|
|
73
|
+
this.logger_.error(`LINE callback validation failed: No state parameter provided - code: ${code ? "present" : "missing"}`);
|
|
74
|
+
return { success: false, error: "No state parameter provided" };
|
|
75
|
+
}
|
|
76
|
+
const state = await authIdentityService.getState(stateKey);
|
|
59
77
|
if (!state) {
|
|
60
|
-
|
|
78
|
+
this.logger_.error(`LINE callback validation failed: Invalid state or session expired - stateKey: ${stateKey}`);
|
|
79
|
+
return { success: false, error: "Invalid state or session expired" };
|
|
61
80
|
}
|
|
62
81
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
this.logger_.info(`Starting LINE token exchange - hasCode: ${!!code}, hasState: ${!!stateKey}`);
|
|
83
|
+
const tokenResponse = await this.exchangeCodeForTokens(code, state.callback_url);
|
|
84
|
+
this.logger_.info("LINE token exchange successful, verifying ID token");
|
|
85
|
+
const idTokenPayload = await this.verifyIdToken(tokenResponse.id_token);
|
|
86
|
+
this.logger_.info("ID token verified, fetching user profile");
|
|
87
|
+
const profile = await this.fetchUserProfile(tokenResponse.access_token);
|
|
88
|
+
this.logger_.info(`LINE user profile fetched successfully - userId: ${profile.userId}, displayName: ${profile.displayName}, hasEmail: ${!!idTokenPayload.email}`);
|
|
89
|
+
const { authIdentity } = await this.findOrCreateAuthIdentity(idTokenPayload, profile, tokenResponse, authIdentityService);
|
|
90
|
+
// Store in Redis using auth_identity_id as key for easy retrieval
|
|
91
|
+
if (this.redisHelper && !authIdentity.app_metadata?.customer_id) {
|
|
92
|
+
await this.redisHelper.storePendingCustomer(authIdentity.id, {
|
|
93
|
+
line_user_id: profile.userId,
|
|
94
|
+
email: idTokenPayload.email,
|
|
95
|
+
display_name: profile.displayName,
|
|
96
|
+
picture_url: profile.pictureUrl,
|
|
97
|
+
status_message: profile.statusMessage,
|
|
98
|
+
name: idTokenPayload.name,
|
|
99
|
+
auth_identity_id: authIdentity.id,
|
|
100
|
+
});
|
|
101
|
+
this.logger_.info(`Stored pending customer in Redis with auth_id: ${authIdentity.id}`);
|
|
102
|
+
}
|
|
82
103
|
return {
|
|
83
|
-
success,
|
|
104
|
+
success: true,
|
|
84
105
|
authIdentity,
|
|
85
106
|
};
|
|
86
107
|
}
|
|
87
108
|
catch (error) {
|
|
88
|
-
|
|
109
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
110
|
+
const errorStack = error instanceof Error ? error.stack : undefined;
|
|
111
|
+
this.logger_.error(`LINE callback validation failed: ${errorMessage} - code: ${code ? "present" : "missing"}, state: ${stateKey ? "present" : "missing"}, stack: ${errorStack}`);
|
|
112
|
+
return { success: false, error: errorMessage };
|
|
89
113
|
}
|
|
90
114
|
}
|
|
91
|
-
async
|
|
92
|
-
|
|
93
|
-
|
|
115
|
+
async exchangeCodeForTokens(code, redirectUri) {
|
|
116
|
+
const response = await fetch(this.LINE_TOKEN_ENDPOINT, {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: {
|
|
119
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
120
|
+
},
|
|
121
|
+
body: new URLSearchParams({
|
|
122
|
+
grant_type: "authorization_code",
|
|
123
|
+
code: code,
|
|
124
|
+
client_id: this.options_.lineChannelId,
|
|
125
|
+
client_secret: this.options_.lineChannelSecret,
|
|
126
|
+
redirect_uri: redirectUri,
|
|
127
|
+
}),
|
|
128
|
+
});
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
const errorData = await response.text();
|
|
131
|
+
this.logger_.error(`LINE token exchange failed - status: ${response.status}, statusText: ${response.statusText}, errorData: ${errorData}, clientId: ${this.options_.lineChannelId}`);
|
|
132
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Failed to exchange authorization code: ${response.status} ${errorData}`);
|
|
133
|
+
}
|
|
134
|
+
return response.json();
|
|
135
|
+
}
|
|
136
|
+
async verifyIdToken(idToken) {
|
|
137
|
+
const decoded = jsonwebtoken_1.default.decode(idToken, { complete: true });
|
|
138
|
+
if (!decoded) {
|
|
139
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Failed to decode ID token");
|
|
140
|
+
}
|
|
141
|
+
const payload = decoded.payload;
|
|
142
|
+
if (payload.aud !== this.options_.lineChannelId) {
|
|
143
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "ID token audience mismatch");
|
|
144
|
+
}
|
|
145
|
+
if (payload.iss !== "https://access.line.me") {
|
|
146
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "ID token issuer mismatch");
|
|
94
147
|
}
|
|
95
|
-
const
|
|
96
|
-
|
|
148
|
+
const now = Math.floor(Date.now() / 1000);
|
|
149
|
+
if (payload.exp < now) {
|
|
150
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "ID token has expired");
|
|
151
|
+
}
|
|
152
|
+
return payload;
|
|
153
|
+
}
|
|
154
|
+
async fetchUserProfile(accessToken) {
|
|
155
|
+
const response = await fetch(this.LINE_PROFILE_ENDPOINT, {
|
|
156
|
+
headers: {
|
|
157
|
+
Authorization: `Bearer ${accessToken}`,
|
|
158
|
+
},
|
|
97
159
|
});
|
|
98
|
-
|
|
99
|
-
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
const errorData = await response.text();
|
|
162
|
+
this.logger_.error(`Failed to fetch LINE profile - status: ${response.status}, statusText: ${response.statusText}, errorData: ${errorData}`);
|
|
163
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Failed to fetch LINE profile: ${response.status} ${errorData}`);
|
|
164
|
+
}
|
|
165
|
+
return response.json();
|
|
166
|
+
}
|
|
167
|
+
async findOrCreateAuthIdentity(idTokenPayload, profile, tokenResponse, authIdentityService) {
|
|
168
|
+
const entity_id = profile.userId;
|
|
100
169
|
const userMetadata = {
|
|
101
|
-
|
|
102
|
-
|
|
170
|
+
// New format for consistency
|
|
171
|
+
userId: profile.userId,
|
|
172
|
+
displayName: profile.displayName,
|
|
173
|
+
pictureUrl: profile.pictureUrl,
|
|
174
|
+
// Legacy format for backwards compatibility
|
|
175
|
+
line_user_id: profile.userId,
|
|
176
|
+
display_name: profile.displayName,
|
|
177
|
+
picture_url: profile.pictureUrl,
|
|
178
|
+
status_message: profile.statusMessage,
|
|
179
|
+
email: idTokenPayload.email,
|
|
180
|
+
name: idTokenPayload.name || profile.displayName,
|
|
181
|
+
picture: idTokenPayload.picture || profile.pictureUrl,
|
|
182
|
+
first_name: (idTokenPayload.name || profile.displayName || "").split(" ")[0] ||
|
|
183
|
+
profile.displayName,
|
|
184
|
+
last_name: (idTokenPayload.name || profile.displayName || "")
|
|
185
|
+
.split(" ")
|
|
186
|
+
.slice(1)
|
|
187
|
+
.join(" ") || "",
|
|
188
|
+
needs_customer_creation: this.options_.autoCreateCustomer,
|
|
189
|
+
};
|
|
190
|
+
// Store tokens in provider metadata for potential later use
|
|
191
|
+
const providerMetadata = {
|
|
192
|
+
access_token: tokenResponse.access_token,
|
|
193
|
+
refresh_token: tokenResponse.refresh_token,
|
|
194
|
+
expires_in: tokenResponse.expires_in,
|
|
195
|
+
token_type: tokenResponse.token_type,
|
|
196
|
+
scope: tokenResponse.scope,
|
|
103
197
|
};
|
|
104
198
|
let authIdentity;
|
|
105
199
|
try {
|
|
106
|
-
authIdentity = await authIdentityService.retrieve({
|
|
107
|
-
|
|
200
|
+
authIdentity = await authIdentityService.retrieve({ entity_id });
|
|
201
|
+
authIdentity = await authIdentityService.update(entity_id, {
|
|
202
|
+
user_metadata: userMetadata,
|
|
203
|
+
provider_metadata: providerMetadata,
|
|
108
204
|
});
|
|
109
205
|
}
|
|
110
206
|
catch (error) {
|
|
111
207
|
if (error.type === utils_1.MedusaError.Types.NOT_FOUND) {
|
|
112
|
-
|
|
208
|
+
this.logger_.info(`Creating new auth identity for LINE user - entity_id: ${entity_id}, displayName: ${userMetadata.display_name}, email: ${userMetadata.email || `line_${entity_id}@line.me`}`);
|
|
209
|
+
authIdentity = await authIdentityService.create({
|
|
113
210
|
entity_id,
|
|
114
211
|
user_metadata: userMetadata,
|
|
212
|
+
provider_metadata: providerMetadata,
|
|
115
213
|
});
|
|
116
|
-
authIdentity
|
|
214
|
+
this.logger_.info(`Auth identity created successfully - authIdentityId: ${authIdentity.id}, entity_id: ${entity_id}`);
|
|
117
215
|
}
|
|
118
216
|
else {
|
|
119
|
-
|
|
217
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
218
|
+
this.logger_.error(`Failed to find or create auth identity - error: ${errorMessage}, entity_id: ${entity_id}`);
|
|
219
|
+
throw error;
|
|
120
220
|
}
|
|
121
221
|
}
|
|
122
|
-
return {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
222
|
+
return { authIdentity };
|
|
223
|
+
}
|
|
224
|
+
async refreshToken(refreshToken) {
|
|
225
|
+
try {
|
|
226
|
+
const response = await fetch(this.LINE_TOKEN_ENDPOINT, {
|
|
227
|
+
method: "POST",
|
|
228
|
+
headers: {
|
|
229
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
230
|
+
},
|
|
231
|
+
body: new URLSearchParams({
|
|
232
|
+
grant_type: "refresh_token",
|
|
233
|
+
refresh_token: refreshToken,
|
|
234
|
+
client_id: this.options_.lineChannelId,
|
|
235
|
+
client_secret: this.options_.lineChannelSecret,
|
|
236
|
+
}),
|
|
237
|
+
});
|
|
238
|
+
if (!response.ok) {
|
|
239
|
+
this.logger_.error(`Failed to refresh LINE token: ${response.status}`);
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
return response.json();
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
this.logger_.error("Error refreshing LINE token:", error);
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async revokeToken(accessToken) {
|
|
250
|
+
try {
|
|
251
|
+
const response = await fetch("https://api.line.me/oauth2/v2.1/revoke", {
|
|
252
|
+
method: "POST",
|
|
253
|
+
headers: {
|
|
254
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
255
|
+
},
|
|
256
|
+
body: new URLSearchParams({
|
|
257
|
+
access_token: accessToken,
|
|
258
|
+
client_id: this.options_.lineChannelId,
|
|
259
|
+
client_secret: this.options_.lineChannelSecret,
|
|
260
|
+
}),
|
|
261
|
+
});
|
|
262
|
+
return response.ok;
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
this.logger_.error("Error revoking LINE token:", error);
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
126
268
|
}
|
|
127
269
|
getRedirect(clientId, callbackUrl, stateKey) {
|
|
270
|
+
const nonce = crypto_1.default.randomBytes(16).toString("hex");
|
|
128
271
|
const authUrl = new URL(`https://access.line.me/oauth2/v2.1/authorize`);
|
|
129
272
|
authUrl.searchParams.set("response_type", "code");
|
|
130
|
-
authUrl.searchParams.set("scope", "profile openid");
|
|
273
|
+
authUrl.searchParams.set("scope", "profile openid email");
|
|
131
274
|
authUrl.searchParams.set("client_id", clientId);
|
|
132
275
|
authUrl.searchParams.set("redirect_uri", callbackUrl);
|
|
133
276
|
authUrl.searchParams.set("state", stateKey);
|
|
277
|
+
authUrl.searchParams.set("nonce", nonce);
|
|
134
278
|
return { success: true, location: authUrl.toString() };
|
|
135
279
|
}
|
|
136
280
|
}
|
|
137
281
|
LineProviderService.identifier = "line";
|
|
138
282
|
LineProviderService.DISPLAY_NAME = "LINE";
|
|
139
283
|
exports.default = LineProviderService;
|
|
140
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9wcm92aWRlcnMvbGluZS9zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEscURBR21DO0FBT25DLGdFQUErQztBQUMvQyxvREFBNEI7QUFZNUIsTUFBTSxtQkFBb0IsU0FBUSxrQ0FBMEI7SUFNMUQsWUFBWSxFQUFFLE1BQU0sRUFBd0IsRUFBRSxPQUFnQjtRQUM1RCxLQUFLLEVBQUUsQ0FBQztRQUVSLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDO1FBQ3RCLElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDO0lBQzFCLENBQUM7SUFFRCxNQUFNLENBQUMsZUFBZSxDQUFDLE9BQXlCO1FBQzlDLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1FBQ2pELENBQUM7UUFDRCxJQUFJLENBQUMsT0FBTyxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDL0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3JELENBQUM7UUFDRCxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQztRQUM5QyxDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxRQUFRLENBQ1osSUFBeUIsRUFDekIsbUJBQWdEO1FBRWhELE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQzdCLHdFQUF3RSxDQUN6RSxDQUFDO0lBQ0osQ0FBQztJQUVELEtBQUssQ0FBQyxZQUFZLENBQ2hCLElBQXlCLEVBQ3pCLG1CQUFnRDtRQUVoRCxNQUFNLEtBQUssR0FBMkIsSUFBSSxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7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
|
|
284
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9wcm92aWRlcnMvbGluZS9zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEscURBR21DO0FBT25DLGdFQUErQztBQUMvQyxvREFBNEI7QUFDNUIsaURBQWlEO0FBK0NqRCxNQUFNLG1CQUFvQixTQUFRLGtDQUEwQjtJQVUzRCxZQUFZLFlBQWtDLEVBQUUsT0FBZ0I7UUFDL0QsS0FBSyxFQUFFLENBQUM7UUFMUSx3QkFBbUIsR0FDbkMsdUNBQXVDLENBQUM7UUFDeEIsMEJBQXFCLEdBQUcsZ0NBQWdDLENBQUM7UUFLekUsSUFBSSxDQUFDLE9BQU8sR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDO1FBQ25DLElBQUksQ0FBQyxRQUFRLEdBQUc7WUFDZixrQkFBa0IsRUFBRSxJQUFJO1lBQ3hCLGVBQWUsRUFBRSxJQUFJO1lBQ3JCLG9CQUFvQixFQUFFLElBQUk7WUFDMUIsR0FBRyxPQUFPO1NBQ1YsQ0FBQztRQUVGLG1EQUFtRDtRQUNuRCxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztZQUNsRSxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksOEJBQWUsQ0FDckMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQ3RCLElBQUksQ0FBQyxPQUFPLENBQ1osQ0FBQztRQUNILENBQUM7SUFDRixDQUFDO0lBRUQsTUFBTSxDQUFDLGVBQWUsQ0FBQyxPQUF5QjtRQUMvQyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQzVCLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQztRQUNoRCxDQUFDO1FBQ0QsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQ2hDLE1BQU0sSUFBSSxLQUFLLENBQUMsaUNBQWlD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
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL2xpbmUvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RateLimiter = void 0;
|
|
7
|
+
exports.generateState = generateState;
|
|
8
|
+
exports.generateNonce = generateNonce;
|
|
9
|
+
exports.generatePlaceholderEmail = generatePlaceholderEmail;
|
|
10
|
+
exports.parseDisplayName = parseDisplayName;
|
|
11
|
+
exports.validateChannelId = validateChannelId;
|
|
12
|
+
exports.validateCallbackUrl = validateCallbackUrl;
|
|
13
|
+
exports.sanitizeInput = sanitizeInput;
|
|
14
|
+
exports.createAuditLog = createAuditLog;
|
|
15
|
+
exports.handleLineApiError = handleLineApiError;
|
|
16
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
17
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
18
|
+
/**
|
|
19
|
+
* Generates a secure state parameter for OAuth flow
|
|
20
|
+
*/
|
|
21
|
+
function generateState() {
|
|
22
|
+
return crypto_1.default.randomBytes(32).toString("hex");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generates a nonce for ID token validation
|
|
26
|
+
*/
|
|
27
|
+
function generateNonce() {
|
|
28
|
+
return crypto_1.default.randomBytes(16).toString("hex");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates a placeholder email for LINE users without email
|
|
32
|
+
*/
|
|
33
|
+
function generatePlaceholderEmail(lineUserId, domain = "line.local") {
|
|
34
|
+
return `line-${lineUserId}@${domain}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extracts first and last name from display name
|
|
38
|
+
*/
|
|
39
|
+
function parseDisplayName(displayName) {
|
|
40
|
+
const parts = displayName.trim().split(" ");
|
|
41
|
+
const firstName = parts[0] || "";
|
|
42
|
+
const lastName = parts.slice(1).join(" ") || "";
|
|
43
|
+
return { firstName, lastName };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Validates LINE Channel ID format
|
|
47
|
+
*/
|
|
48
|
+
function validateChannelId(channelId) {
|
|
49
|
+
return /^\d{10}$/.test(channelId);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Validates callback URL
|
|
53
|
+
*/
|
|
54
|
+
function validateCallbackUrl(url) {
|
|
55
|
+
try {
|
|
56
|
+
const parsed = new URL(url);
|
|
57
|
+
return parsed.protocol === "https:" || parsed.hostname === "localhost";
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Rate limit tracker for API calls
|
|
65
|
+
*/
|
|
66
|
+
class RateLimiter {
|
|
67
|
+
constructor(maxAttempts = 10, windowMs = 60000) {
|
|
68
|
+
this.attempts = new Map();
|
|
69
|
+
this.maxAttempts = maxAttempts;
|
|
70
|
+
this.windowMs = windowMs;
|
|
71
|
+
}
|
|
72
|
+
isAllowed(key) {
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
const attempts = this.attempts.get(key) || [];
|
|
75
|
+
// Remove expired attempts
|
|
76
|
+
const validAttempts = attempts.filter((timestamp) => now - timestamp < this.windowMs);
|
|
77
|
+
if (validAttempts.length >= this.maxAttempts) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
validAttempts.push(now);
|
|
81
|
+
this.attempts.set(key, validAttempts);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
reset(key) {
|
|
85
|
+
this.attempts.delete(key);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.RateLimiter = RateLimiter;
|
|
89
|
+
/**
|
|
90
|
+
* Sanitizes user input to prevent injection attacks
|
|
91
|
+
*/
|
|
92
|
+
function sanitizeInput(input) {
|
|
93
|
+
return input
|
|
94
|
+
.replace(/[<>]/g, "")
|
|
95
|
+
.replace(/javascript:/gi, "")
|
|
96
|
+
.trim();
|
|
97
|
+
}
|
|
98
|
+
function createAuditLog(entry) {
|
|
99
|
+
return {
|
|
100
|
+
...entry,
|
|
101
|
+
timestamp: new Date(),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Handles LINE API errors
|
|
106
|
+
*/
|
|
107
|
+
function handleLineApiError(status, message) {
|
|
108
|
+
const errorMessages = {
|
|
109
|
+
400: "Invalid request to LINE API",
|
|
110
|
+
401: "LINE authentication failed",
|
|
111
|
+
403: "Access forbidden by LINE",
|
|
112
|
+
429: "Too many requests to LINE API",
|
|
113
|
+
500: "LINE server error",
|
|
114
|
+
503: "LINE service temporarily unavailable",
|
|
115
|
+
};
|
|
116
|
+
const errorMessage = errorMessages[status] || `LINE API error: ${status}`;
|
|
117
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `${errorMessage}: ${message}`);
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL2xpbmUvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBTUEsc0NBRUM7QUFLRCxzQ0FFQztBQUtELDREQUVDO0FBS0QsNENBUUM7QUFLRCw4Q0FFQztBQUtELGtEQU9DO0FBMENELHNDQUtDO0FBZUQsd0NBS0M7QUFLRCxnREFnQkM7QUE5SUQsb0RBQTRCO0FBQzVCLHFEQUF3RDtBQUV4RDs7R0FFRztBQUNILFNBQWdCLGFBQWE7SUFDM0IsT0FBTyxnQkFBTSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDaEQsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsYUFBYTtJQUMzQixPQUFPLGdCQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNoRCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQix3QkFBd0IsQ0FBQyxVQUFrQixFQUFFLE1BQU0sR0FBRyxZQUFZO0lBQ2hGLE9BQU8sUUFBUSxVQUFVLElBQUksTUFBTSxFQUFFLENBQUM7QUFDeEMsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsZ0JBQWdCLENBQUMsV0FBbUI7SUFJbEQsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM1QyxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2pDLE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNoRCxPQUFPLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxDQUFDO0FBQ2pDLENB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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lodashventure/medusa-login-provider",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "A starter for Medusa plugins.",
|
|
5
5
|
"author": "Medusa (https://medusajs.com)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
"./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
|
|
14
14
|
"./modules/*": "./.medusa/server/src/modules/*/index.js",
|
|
15
15
|
"./providers/*": "./.medusa/server/src/providers/*/index.js",
|
|
16
|
-
"
|
|
16
|
+
"./providers/line": "./.medusa/server/src/providers/line/index.js",
|
|
17
|
+
"./*": "./.medusa/server/src/*.js",
|
|
18
|
+
".": "./.medusa/server/src/index.js"
|
|
17
19
|
},
|
|
18
20
|
"keywords": [
|
|
19
21
|
"medusa",
|
|
@@ -24,7 +26,16 @@
|
|
|
24
26
|
],
|
|
25
27
|
"scripts": {
|
|
26
28
|
"build": "medusa plugin:build",
|
|
27
|
-
"dev": "medusa plugin:develop"
|
|
29
|
+
"dev": "medusa plugin:develop",
|
|
30
|
+
"test": "jest",
|
|
31
|
+
"test:watch": "jest --watch",
|
|
32
|
+
"test:coverage": "jest --coverage",
|
|
33
|
+
"test:ci": "jest --ci --coverage --watchAll=false",
|
|
34
|
+
"test:unit": "jest src/**/*.test.ts --testPathIgnorePatterns=e2e",
|
|
35
|
+
"test:integration": "jest src/api/__tests__/**/*.test.ts",
|
|
36
|
+
"test:e2e": "jest src/__tests__/e2e/**/*.test.ts",
|
|
37
|
+
"lint": "eslint src --ext .ts --fix",
|
|
38
|
+
"type-check": "tsc --noEmit"
|
|
28
39
|
},
|
|
29
40
|
"devDependencies": {
|
|
30
41
|
"@medusajs/admin-sdk": "2.10.0",
|
|
@@ -40,15 +51,25 @@
|
|
|
40
51
|
"@mikro-orm/migrations": "6.4.3",
|
|
41
52
|
"@mikro-orm/postgresql": "6.4.3",
|
|
42
53
|
"@swc/core": "1.5.7",
|
|
54
|
+
"@types/jest": "^29.5.0",
|
|
43
55
|
"@types/jsonwebtoken": "^9",
|
|
44
56
|
"@types/node": "^20.0.0",
|
|
45
57
|
"@types/react": "^18.3.2",
|
|
46
58
|
"@types/react-dom": "^18.2.25",
|
|
59
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
60
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
47
61
|
"awilix": "^8.0.1",
|
|
62
|
+
"eslint": "^8.40.0",
|
|
63
|
+
"jest": "^29.5.0",
|
|
64
|
+
"jest-junit": "^16.0.0",
|
|
65
|
+
"jest-watch-typeahead": "^2.2.2",
|
|
66
|
+
"node-fetch": "^3.3.1",
|
|
48
67
|
"pg": "^8.13.0",
|
|
49
68
|
"prop-types": "^15.8.1",
|
|
50
69
|
"react": "^18.2.0",
|
|
51
70
|
"react-dom": "^18.2.0",
|
|
71
|
+
"reflect-metadata": "^0.1.13",
|
|
72
|
+
"ts-jest": "^29.1.0",
|
|
52
73
|
"ts-node": "^10.9.2",
|
|
53
74
|
"typescript": "^5.6.2",
|
|
54
75
|
"vite": "^5.2.11",
|
|
@@ -74,6 +95,8 @@
|
|
|
74
95
|
"node": ">=20"
|
|
75
96
|
},
|
|
76
97
|
"dependencies": {
|
|
98
|
+
"@types/ioredis": "^4.28.10",
|
|
99
|
+
"ioredis": "^5.8.0",
|
|
77
100
|
"jsonwebtoken": "^9.0.2"
|
|
78
101
|
}
|
|
79
102
|
}
|