@lodashventure/medusa-login-provider 4.1.3 → 4.1.4

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.
@@ -1,438 +0,0 @@
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
- const service_1 = __importDefault(require("../service"));
7
- const utils_1 = require("@medusajs/framework/utils");
8
- const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
9
- const crypto_1 = __importDefault(require("crypto"));
10
- // Mock dependencies
11
- jest.mock("jsonwebtoken");
12
- jest.mock("crypto");
13
- // Mock fetch globally
14
- global.fetch = jest.fn();
15
- describe("LineProviderService", () => {
16
- let service;
17
- let mockLogger;
18
- let mockCustomerService;
19
- let mockAuthIdentityService;
20
- let mockFetch;
21
- let mockCrypto;
22
- let mockJwt;
23
- const defaultOptions = {
24
- lineChannelId: "1234567890",
25
- lineChannelSecret: "test-secret",
26
- lineRedirectUrl: "https://example.com/callback",
27
- autoCreateCustomer: true,
28
- syncProfileData: true,
29
- };
30
- beforeEach(() => {
31
- jest.clearAllMocks();
32
- mockFetch = global.fetch;
33
- mockCrypto = crypto_1.default;
34
- mockJwt = jsonwebtoken_1.default;
35
- mockLogger = {
36
- info: jest.fn(),
37
- error: jest.fn(),
38
- warn: jest.fn(),
39
- debug: jest.fn(),
40
- };
41
- mockCustomerService = {
42
- create: jest.fn(),
43
- update: jest.fn(),
44
- retrieve: jest.fn(),
45
- listAndCount: jest.fn(),
46
- };
47
- mockAuthIdentityService = {
48
- create: jest.fn(),
49
- update: jest.fn(),
50
- retrieve: jest.fn(),
51
- setState: jest.fn(),
52
- getState: jest.fn(),
53
- };
54
- service = new service_1.default({
55
- logger: mockLogger,
56
- customerService: mockCustomerService,
57
- }, defaultOptions);
58
- // Mock crypto.randomBytes
59
- const mockBuffer = Buffer.from("a".repeat(32));
60
- mockCrypto.randomBytes.mockReturnValue(mockBuffer);
61
- });
62
- describe("validateOptions", () => {
63
- it("should validate required options", () => {
64
- expect(() => {
65
- service_1.default.validateOptions({});
66
- }).toThrow("line channel id is required");
67
- expect(() => {
68
- service_1.default.validateOptions({
69
- lineChannelId: "123",
70
- });
71
- }).toThrow("line channel secret is required");
72
- expect(() => {
73
- service_1.default.validateOptions({
74
- lineChannelId: "123",
75
- lineChannelSecret: "secret",
76
- });
77
- }).not.toThrow(); // Redirect URL is now optional
78
- // Validation should pass with just channel ID and secret
79
- });
80
- });
81
- describe("register", () => {
82
- it("should throw NOT_ALLOWED error", async () => {
83
- await expect(service.register({}, mockAuthIdentityService)).rejects.toThrow(utils_1.MedusaError);
84
- });
85
- });
86
- describe("authenticate", () => {
87
- it("should return redirect URL for LINE OAuth", async () => {
88
- mockAuthIdentityService.setState.mockResolvedValue(undefined);
89
- const result = await service.authenticate({ body: { callback_url: "https://example.com/callback" } }, mockAuthIdentityService);
90
- expect(result.success).toBe(true);
91
- expect(result.location).toContain("https://access.line.me/oauth2/v2.1/authorize");
92
- expect(result.location).toContain("client_id=1234567890");
93
- expect(result.location).toContain("scope=profile%20openid%20email");
94
- expect(mockAuthIdentityService.setState).toHaveBeenCalled();
95
- });
96
- it("should handle authentication errors", async () => {
97
- const result = await service.authenticate({
98
- query: {
99
- error: "access_denied",
100
- error_description: "User denied access",
101
- error_uri: "https://example.com/error",
102
- },
103
- }, mockAuthIdentityService);
104
- expect(result.success).toBe(false);
105
- expect(result.error).toContain("User denied access");
106
- });
107
- });
108
- describe("validateCallback", () => {
109
- const mockTokenResponse = {
110
- access_token: "test-access-token",
111
- id_token: "test-id-token",
112
- refresh_token: "test-refresh-token",
113
- expires_in: 2592000,
114
- scope: "profile openid",
115
- token_type: "Bearer",
116
- };
117
- const mockProfile = {
118
- userId: "U1234567890",
119
- displayName: "Test User",
120
- pictureUrl: "https://example.com/picture.jpg",
121
- };
122
- const mockIdTokenPayload = {
123
- iss: "https://access.line.me",
124
- sub: "U1234567890",
125
- aud: "1234567890",
126
- exp: Math.floor(Date.now() / 1000) + 3600,
127
- iat: Math.floor(Date.now() / 1000),
128
- name: "Test User",
129
- picture: "https://example.com/picture.jpg",
130
- };
131
- it("should handle missing authorization code", async () => {
132
- const result = await service.validateCallback({ query: {}, body: {} }, mockAuthIdentityService);
133
- expect(result.success).toBe(false);
134
- expect(result.error).toBe("No authorization code provided");
135
- });
136
- it("should handle missing state", async () => {
137
- const result = await service.validateCallback({ query: { code: "test-code" }, body: {} }, mockAuthIdentityService);
138
- expect(result.success).toBe(false);
139
- expect(result.error).toBe("No state parameter provided");
140
- });
141
- it("should handle invalid state", async () => {
142
- mockAuthIdentityService.getState.mockResolvedValue(null);
143
- const result = await service.validateCallback({ query: { code: "test-code", state: "invalid-state" }, body: {} }, mockAuthIdentityService);
144
- expect(result.success).toBe(false);
145
- expect(result.error).toBe("Invalid state or session expired");
146
- });
147
- it("should handle OAuth errors", async () => {
148
- const result = await service.validateCallback({
149
- query: {
150
- error: "invalid_request",
151
- error_description: "Invalid request",
152
- },
153
- body: {},
154
- }, mockAuthIdentityService);
155
- expect(result.success).toBe(false);
156
- expect(result.error).toContain("Invalid request");
157
- });
158
- it("should successfully validate callback with complete flow", async () => {
159
- // Setup mocks
160
- mockAuthIdentityService.getState.mockResolvedValue({
161
- callback_url: "https://example.com/callback",
162
- });
163
- // Mock token exchange
164
- mockFetch.mockResolvedValueOnce({
165
- ok: true,
166
- json: () => Promise.resolve(mockTokenResponse),
167
- });
168
- // Mock ID token verification
169
- mockJwt.decode.mockReturnValue({
170
- payload: mockIdTokenPayload,
171
- });
172
- // Mock profile fetch
173
- mockFetch.mockResolvedValueOnce({
174
- ok: true,
175
- json: () => Promise.resolve(mockProfile),
176
- });
177
- // Mock auth identity creation (new user)
178
- mockAuthIdentityService.retrieve.mockRejectedValue(new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "Not found"));
179
- const mockAuthIdentity = {
180
- entity_id: "U1234567890",
181
- user_metadata: {
182
- line_user_id: "U1234567890",
183
- display_name: "Test User",
184
- picture_url: "https://example.com/picture.jpg",
185
- name: "Test User",
186
- picture: "https://example.com/picture.jpg",
187
- },
188
- };
189
- mockAuthIdentityService.create.mockResolvedValue(mockAuthIdentity);
190
- // Mock customer creation
191
- const mockCustomer = {
192
- id: "cust_123",
193
- email: "line-U1234567890@line.local",
194
- first_name: "Test",
195
- last_name: "User",
196
- };
197
- mockCustomerService.create.mockResolvedValue(mockCustomer);
198
- const result = await service.validateCallback({ query: { code: "test-code", state: "valid-state" }, body: {} }, mockAuthIdentityService);
199
- expect(result.success).toBe(true);
200
- expect(result.authIdentity).toBe(mockAuthIdentity);
201
- });
202
- it("should handle existing user with profile sync", async () => {
203
- mockAuthIdentityService.getState.mockResolvedValue({
204
- callback_url: "https://example.com/callback",
205
- });
206
- mockFetch.mockResolvedValueOnce({
207
- ok: true,
208
- json: () => Promise.resolve(mockTokenResponse),
209
- });
210
- mockJwt.decode.mockReturnValue({
211
- payload: mockIdTokenPayload,
212
- });
213
- mockFetch.mockResolvedValueOnce({
214
- ok: true,
215
- json: () => Promise.resolve(mockProfile),
216
- });
217
- // Mock existing auth identity
218
- const existingAuthIdentity = {
219
- entity_id: "U1234567890",
220
- user_metadata: {
221
- line_user_id: "U1234567890",
222
- display_name: "Old Name",
223
- },
224
- };
225
- mockAuthIdentityService.retrieve.mockResolvedValue(existingAuthIdentity);
226
- const updatedAuthIdentity = {
227
- ...existingAuthIdentity,
228
- user_metadata: {
229
- line_user_id: "U1234567890",
230
- display_name: "Test User",
231
- picture_url: "https://example.com/picture.jpg",
232
- },
233
- };
234
- mockAuthIdentityService.update.mockResolvedValue(updatedAuthIdentity);
235
- // Mock existing customer
236
- mockCustomerService.listAndCount.mockResolvedValue([
237
- [{
238
- id: "cust_existing",
239
- metadata: { line_user_id: "U1234567890" }
240
- }],
241
- 1
242
- ]);
243
- const result = await service.validateCallback({ query: { code: "test-code", state: "valid-state" }, body: {} }, mockAuthIdentityService);
244
- expect(result.success).toBe(true);
245
- expect(mockAuthIdentityService.update).toHaveBeenCalled();
246
- });
247
- });
248
- describe("verifyIdToken", () => {
249
- beforeEach(() => {
250
- jest.spyOn(Date, "now").mockReturnValue(1000000);
251
- });
252
- afterEach(() => {
253
- Date.now.mockRestore();
254
- });
255
- it("should verify valid ID token", async () => {
256
- const payload = {
257
- iss: "https://access.line.me",
258
- sub: "U123456",
259
- aud: "1234567890",
260
- exp: 1001, // Future timestamp
261
- iat: 900,
262
- };
263
- mockJwt.decode.mockReturnValue({
264
- payload,
265
- });
266
- const result = await service.verifyIdToken("valid-token");
267
- expect(result).toBe(payload);
268
- });
269
- it("should reject token with wrong audience", async () => {
270
- const payload = {
271
- iss: "https://access.line.me",
272
- sub: "U123456",
273
- aud: "wrong-channel-id",
274
- exp: 1001,
275
- iat: 900,
276
- };
277
- mockJwt.decode.mockReturnValue({
278
- payload,
279
- });
280
- await expect(service.verifyIdToken("invalid-token")).rejects.toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "ID token audience mismatch"));
281
- });
282
- it("should reject token with wrong issuer", async () => {
283
- const payload = {
284
- iss: "https://wrong-issuer.com",
285
- sub: "U123456",
286
- aud: "1234567890",
287
- exp: 1001,
288
- iat: 900,
289
- };
290
- mockJwt.decode.mockReturnValue({
291
- payload,
292
- });
293
- await expect(service.verifyIdToken("invalid-token")).rejects.toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "ID token issuer mismatch"));
294
- });
295
- it("should reject expired token", async () => {
296
- const payload = {
297
- iss: "https://access.line.me",
298
- sub: "U123456",
299
- aud: "1234567890",
300
- exp: 999, // Past timestamp
301
- iat: 900,
302
- };
303
- mockJwt.decode.mockReturnValue({
304
- payload,
305
- });
306
- await expect(service.verifyIdToken("expired-token")).rejects.toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "ID token has expired"));
307
- });
308
- it("should handle malformed ID token", async () => {
309
- mockJwt.decode.mockReturnValue(null);
310
- await expect(service.verifyIdToken("malformed-token")).rejects.toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Failed to decode ID token"));
311
- });
312
- });
313
- describe("Token Management", () => {
314
- beforeEach(() => {
315
- global.fetch = jest.fn();
316
- });
317
- describe("refreshToken", () => {
318
- it("should refresh LINE access token", async () => {
319
- const mockResponse = {
320
- access_token: "new-access-token",
321
- expires_in: 2592000,
322
- refresh_token: "new-refresh-token",
323
- };
324
- global.fetch.mockResolvedValue({
325
- ok: true,
326
- json: async () => mockResponse,
327
- });
328
- const result = await service.refreshToken("old-refresh-token");
329
- expect(result).toEqual(mockResponse);
330
- expect(global.fetch).toHaveBeenCalledWith("https://api.line.me/oauth2/v2.1/token", expect.objectContaining({
331
- method: "POST",
332
- headers: {
333
- "Content-Type": "application/x-www-form-urlencoded",
334
- },
335
- }));
336
- });
337
- it("should handle refresh token errors", async () => {
338
- global.fetch.mockResolvedValue({
339
- ok: false,
340
- status: 401,
341
- });
342
- const result = await service.refreshToken("invalid-token");
343
- expect(result).toBeNull();
344
- expect(mockLogger.error).toHaveBeenCalled();
345
- });
346
- });
347
- describe("revokeToken", () => {
348
- it("should revoke LINE access token", async () => {
349
- global.fetch.mockResolvedValue({
350
- ok: true,
351
- });
352
- const result = await service.revokeToken("access-token");
353
- expect(result).toBe(true);
354
- expect(global.fetch).toHaveBeenCalledWith("https://api.line.me/oauth2/v2.1/revoke", expect.objectContaining({
355
- method: "POST",
356
- }));
357
- });
358
- it("should handle revoke token errors", async () => {
359
- global.fetch.mockResolvedValue({
360
- ok: false,
361
- });
362
- const result = await service.revokeToken("invalid-token");
363
- expect(result).toBe(false);
364
- });
365
- });
366
- });
367
- describe("Customer Management", () => {
368
- it("should find existing customer by LINE ID", async () => {
369
- const mockCustomer = {
370
- id: "cus_123",
371
- email: "test@example.com",
372
- metadata: { line_user_id: "U1234567890" },
373
- };
374
- mockCustomerService.listAndCount.mockResolvedValue([
375
- [mockCustomer],
376
- 1,
377
- ]);
378
- const result = await service.findCustomerByLineId("U1234567890");
379
- expect(result).toEqual(mockCustomer);
380
- expect(mockCustomerService.listAndCount).toHaveBeenCalledWith({
381
- metadata: {
382
- line_user_id: "U1234567890",
383
- },
384
- }, {});
385
- });
386
- it("should return null when customer not found", async () => {
387
- mockCustomerService.listAndCount.mockResolvedValue([[], 0]);
388
- const result = await service.findCustomerByLineId("U1234567890");
389
- expect(result).toBeNull();
390
- });
391
- it("should create new customer from LINE profile", async () => {
392
- const mockProfile = {
393
- userId: "U1234567890",
394
- displayName: "John Doe",
395
- pictureUrl: "https://example.com/pic.jpg",
396
- };
397
- const mockIdToken = {
398
- email: "john@example.com",
399
- };
400
- const mockCustomer = {
401
- id: "cus_new",
402
- email: "john@example.com",
403
- first_name: "John",
404
- last_name: "Doe",
405
- };
406
- mockCustomerService.create.mockResolvedValue(mockCustomer);
407
- const result = await service.createCustomerFromLineProfile(mockProfile, mockIdToken);
408
- expect(result).toEqual(mockCustomer);
409
- expect(mockCustomerService.create).toHaveBeenCalledWith({
410
- email: "john@example.com",
411
- first_name: "John",
412
- last_name: "Doe",
413
- metadata: expect.objectContaining({
414
- line_user_id: "U1234567890",
415
- line_display_name: "John Doe",
416
- line_picture_url: "https://example.com/pic.jpg",
417
- created_via: "line_oauth",
418
- }),
419
- });
420
- });
421
- it("should use placeholder email when not provided", async () => {
422
- const mockProfile = {
423
- userId: "U1234567890",
424
- displayName: "Test User",
425
- };
426
- const mockIdToken = {};
427
- mockCustomerService.create.mockResolvedValue({
428
- id: "cus_new",
429
- email: "line-U1234567890@line.local",
430
- });
431
- await service.createCustomerFromLineProfile(mockProfile, mockIdToken);
432
- expect(mockCustomerService.create).toHaveBeenCalledWith(expect.objectContaining({
433
- email: "line-U1234567890@line.local",
434
- }));
435
- });
436
- });
437
- });
438
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL3Byb3ZpZGVycy9saW5lL19fdGVzdHNfXy9zZXJ2aWNlLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx5REFBNkM7QUFDN0MscURBQXdEO0FBQ3hELGdFQUErQjtBQUMvQixvREFBNEI7QUFFNUIsb0JBQW9CO0FBQ3BCLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7QUFDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUVwQixzQkFBc0I7QUFDdEIsTUFBTSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7QUFFekIsUUFBUSxDQUFDLHFCQUFxQixFQUFFLEdBQUcsRUFBRTtJQUNuQyxJQUFJLE9BQTRCLENBQUM7SUFDakMsSUFBSSxVQUFlLENBQUM7SUFDcEIsSUFBSSxtQkFBd0IsQ0FBQztJQUM3QixJQUFJLHVCQUE0QixDQUFDO0lBQ2pDLElBQUksU0FBNEMsQ0FBQztJQUNqRCxJQUFJLFVBQXNDLENBQUM7SUFDM0MsSUFBSSxPQUFnQyxDQUFDO0lBRXJDLE1BQU0sY0FBYyxHQUFHO1FBQ3JCLGFBQWEsRUFBRSxZQUFZO1FBQzNCLGlCQUFpQixFQUFFLGFBQWE7UUFDaEMsZUFBZSxFQUFFLDhCQUE4QjtRQUMvQyxrQkFBa0IsRUFBRSxJQUFJO1FBQ3hCLGVBQWUsRUFBRSxJQUFJO0tBQ3RCLENBQUM7SUFFRixVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ2QsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3JCLFNBQVMsR0FBRyxNQUFNLENBQUMsS0FBMEMsQ0FBQztRQUM5RCxVQUFVLEdBQUcsZ0JBQW9DLENBQUM7UUFDbEQsT0FBTyxHQUFHLHNCQUE4QixDQUFDO1FBRXpDLFVBQVUsR0FBRztZQUNYLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxF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