@hemia/auth-sdk 0.0.2 → 0.0.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.
- package/dist/hemia-auth-sdk.esm.js +228 -215
- package/dist/hemia-auth-sdk.js +226 -213
- package/dist/types/adapters/index.d.ts +1 -0
- package/dist/types/adapters/internal.adapter.d.ts +13 -0
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/controllers/abstract-auth.controller.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/ioc.d.ts +5 -4
- package/dist/types/services/auth.service.d.ts +8 -7
- package/dist/types/services/index.d.ts +0 -1
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/session-storage.interface.d.ts +5 -0
- package/package.json +5 -3
- package/dist/types/services/cache.service.d.ts +0 -8
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
import {
|
|
2
|
+
import { BadRequestError, CustomHttpError, InternalServerError, Get, Req, Res, Post, HttpError } from '@hemia/common';
|
|
3
3
|
import { HMNetworkServices } from '@hemia/network-services';
|
|
4
|
+
import { JwtManager } from '@hemia/jwt-manager';
|
|
4
5
|
import { randomBytes, createHash } from 'crypto';
|
|
5
|
-
import { injectable } from 'inversify';
|
|
6
|
-
import { CacheService } from '@hemia/cache-manager';
|
|
6
|
+
import { injectable, inject } from 'inversify';
|
|
7
7
|
|
|
8
8
|
/******************************************************************************
|
|
9
9
|
Copyright (c) Microsoft Corporation.
|
|
@@ -42,196 +42,6 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
42
42
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
class SessionError extends Error {
|
|
46
|
-
constructor(message, code, redirectTo) {
|
|
47
|
-
super(message);
|
|
48
|
-
this.code = code;
|
|
49
|
-
this.redirectTo = redirectTo;
|
|
50
|
-
this.name = this.constructor.name;
|
|
51
|
-
Error.captureStackTrace(this, this.constructor);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
class SessionNotFoundError extends SessionError {
|
|
55
|
-
constructor(message = 'Sesión no encontrada') {
|
|
56
|
-
super(message, 'SESSION_NOT_FOUND', '/?session=required');
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
class SessionExpiredError extends SessionError {
|
|
60
|
-
constructor(message = 'Sesión expirada') {
|
|
61
|
-
super(message, 'SESSION_EXPIRED', '/session-expired?session=expired');
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
class SessionInvalidError extends SessionError {
|
|
65
|
-
constructor(message = 'Sesión inválida') {
|
|
66
|
-
super(message, 'SESSION_INVALID', '/?session=invalid');
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
class TokenRefreshFailedError extends SessionError {
|
|
70
|
-
constructor(message = 'Error al renovar tokens') {
|
|
71
|
-
super(message, 'TOKEN_REFRESH_FAILED', '/session-expired?session=expired');
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
class InvalidTokenFormatError extends SessionError {
|
|
75
|
-
constructor(message = 'Formato de token inválido') {
|
|
76
|
-
super(message, 'INVALID_TOKEN_FORMAT', '/?session=invalid');
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Controller Abstracto Reutilizable
|
|
82
|
-
* Gestiona automáticamente Login, Callback, Me y Logout.
|
|
83
|
-
*/
|
|
84
|
-
class AbstractAuthController {
|
|
85
|
-
constructor(authService) {
|
|
86
|
-
this.authService = authService;
|
|
87
|
-
}
|
|
88
|
-
async login(req, res) {
|
|
89
|
-
try {
|
|
90
|
-
const autoParam = typeof req.query.auto === 'string' ? req.query.auto : 'false';
|
|
91
|
-
const { loginUrl, tempState } = this.authService.generateLoginParams(autoParam);
|
|
92
|
-
res.cookie('auth_flow', JSON.stringify(tempState), {
|
|
93
|
-
httpOnly: true,
|
|
94
|
-
secure: process.env.NODE_ENV === 'production',
|
|
95
|
-
maxAge: 300000 // 5 min
|
|
96
|
-
});
|
|
97
|
-
res.redirect(loginUrl);
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
console.error('Login Error:', error);
|
|
101
|
-
res.status(500).send('Login initialization failed');
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
async callback(req, res) {
|
|
105
|
-
try {
|
|
106
|
-
const { code, state } = req.query;
|
|
107
|
-
const authFlowCookie = req.cookies['auth_flow'];
|
|
108
|
-
if (!authFlowCookie) {
|
|
109
|
-
res.status(400).send('Missing auth flow cookie');
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
const storedState = JSON.parse(authFlowCookie);
|
|
113
|
-
const result = await this.authService.handleCallback(code, state, storedState);
|
|
114
|
-
res.cookie('x-session', result.sessionId, {
|
|
115
|
-
httpOnly: true,
|
|
116
|
-
secure: process.env.NODE_ENV === 'production',
|
|
117
|
-
sameSite: 'lax',
|
|
118
|
-
maxAge: result.expiresIn * 1000,
|
|
119
|
-
path: '/'
|
|
120
|
-
});
|
|
121
|
-
res.clearCookie('auth_flow');
|
|
122
|
-
res.redirect(result.redirectUrl);
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
console.error('Callback Error:', error);
|
|
126
|
-
if (error instanceof HttpError) {
|
|
127
|
-
res.status(error.statusCode).json({
|
|
128
|
-
success: false,
|
|
129
|
-
message: error.message,
|
|
130
|
-
error: error.error
|
|
131
|
-
});
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
res.status(500).json({
|
|
135
|
-
success: false,
|
|
136
|
-
message: 'Failed to complete authentication',
|
|
137
|
-
error: error.message
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
async me(req, res) {
|
|
142
|
-
const sessionId = req.cookies['x-session'];
|
|
143
|
-
if (!sessionId) {
|
|
144
|
-
return res.status(401).json({
|
|
145
|
-
success: false,
|
|
146
|
-
message: 'No session found',
|
|
147
|
-
data: {
|
|
148
|
-
redirect_to: '/?session=required'
|
|
149
|
-
},
|
|
150
|
-
error: {
|
|
151
|
-
message: 'Session is missing',
|
|
152
|
-
code: 'SESSION_MISSING'
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
try {
|
|
157
|
-
const result = await this.authService.getSessionUser(sessionId);
|
|
158
|
-
return res.status(200).json({
|
|
159
|
-
success: true,
|
|
160
|
-
data: result
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
catch (error) {
|
|
164
|
-
res.clearCookie('x-session', {
|
|
165
|
-
httpOnly: true,
|
|
166
|
-
secure: process.env.NODE_ENV === 'production',
|
|
167
|
-
sameSite: 'lax',
|
|
168
|
-
});
|
|
169
|
-
if (error instanceof SessionError) {
|
|
170
|
-
return res.status(401).json({
|
|
171
|
-
success: false,
|
|
172
|
-
message: error.message,
|
|
173
|
-
data: {
|
|
174
|
-
redirect_to: error.redirectTo || '/login'
|
|
175
|
-
},
|
|
176
|
-
error: {
|
|
177
|
-
message: error.message,
|
|
178
|
-
code: error.code
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
return res.status(500).json({
|
|
184
|
-
success: false,
|
|
185
|
-
message: 'Failed to retrieve session user',
|
|
186
|
-
error: error.message
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
async logout(req, res) {
|
|
192
|
-
const sessionId = req.cookies['x-session'];
|
|
193
|
-
if (sessionId) {
|
|
194
|
-
await this.authService.logout(sessionId);
|
|
195
|
-
}
|
|
196
|
-
res.clearCookie('x-session', {
|
|
197
|
-
httpOnly: true,
|
|
198
|
-
secure: process.env.NODE_ENV === 'production',
|
|
199
|
-
sameSite: 'lax',
|
|
200
|
-
});
|
|
201
|
-
return res.status(200).json({ success: true });
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
__decorate([
|
|
205
|
-
Get('/login'),
|
|
206
|
-
__param(0, Req()),
|
|
207
|
-
__param(1, Res()),
|
|
208
|
-
__metadata("design:type", Function),
|
|
209
|
-
__metadata("design:paramtypes", [Object, Object]),
|
|
210
|
-
__metadata("design:returntype", Promise)
|
|
211
|
-
], AbstractAuthController.prototype, "login", null);
|
|
212
|
-
__decorate([
|
|
213
|
-
Get('/callback'),
|
|
214
|
-
__metadata("design:type", Function),
|
|
215
|
-
__metadata("design:paramtypes", [Object, Object]),
|
|
216
|
-
__metadata("design:returntype", Promise)
|
|
217
|
-
], AbstractAuthController.prototype, "callback", null);
|
|
218
|
-
__decorate([
|
|
219
|
-
Get('/me'),
|
|
220
|
-
__param(0, Req()),
|
|
221
|
-
__param(1, Res()),
|
|
222
|
-
__metadata("design:type", Function),
|
|
223
|
-
__metadata("design:paramtypes", [Object, Object]),
|
|
224
|
-
__metadata("design:returntype", Promise)
|
|
225
|
-
], AbstractAuthController.prototype, "me", null);
|
|
226
|
-
__decorate([
|
|
227
|
-
Post('/logout'),
|
|
228
|
-
__param(0, Req()),
|
|
229
|
-
__param(1, Res()),
|
|
230
|
-
__metadata("design:type", Function),
|
|
231
|
-
__metadata("design:paramtypes", [Object, Object]),
|
|
232
|
-
__metadata("design:returntype", Promise)
|
|
233
|
-
], AbstractAuthController.prototype, "logout", null);
|
|
234
|
-
|
|
235
45
|
/**
|
|
236
46
|
* Utilidades para manejo de PKCE y codificación Base64URL
|
|
237
47
|
*/
|
|
@@ -276,31 +86,51 @@ class Generators {
|
|
|
276
86
|
}
|
|
277
87
|
}
|
|
278
88
|
|
|
279
|
-
|
|
280
|
-
constructor(
|
|
281
|
-
|
|
89
|
+
class SessionError extends Error {
|
|
90
|
+
constructor(message, code, redirectTo) {
|
|
91
|
+
super(message);
|
|
92
|
+
this.code = code;
|
|
93
|
+
this.redirectTo = redirectTo;
|
|
94
|
+
this.name = this.constructor.name;
|
|
95
|
+
Error.captureStackTrace(this, this.constructor);
|
|
282
96
|
}
|
|
283
|
-
|
|
284
|
-
|
|
97
|
+
}
|
|
98
|
+
class SessionNotFoundError extends SessionError {
|
|
99
|
+
constructor(message = 'Sesión no encontrada') {
|
|
100
|
+
super(message, 'SESSION_NOT_FOUND', '/?session=required');
|
|
285
101
|
}
|
|
286
|
-
|
|
287
|
-
|
|
102
|
+
}
|
|
103
|
+
class SessionExpiredError extends SessionError {
|
|
104
|
+
constructor(message = 'Sesión expirada') {
|
|
105
|
+
super(message, 'SESSION_EXPIRED', '/session-expired?session=expired');
|
|
288
106
|
}
|
|
289
|
-
|
|
290
|
-
|
|
107
|
+
}
|
|
108
|
+
class SessionInvalidError extends SessionError {
|
|
109
|
+
constructor(message = 'Sesión inválida') {
|
|
110
|
+
super(message, 'SESSION_INVALID', '/?session=invalid');
|
|
291
111
|
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
112
|
+
}
|
|
113
|
+
class TokenRefreshFailedError extends SessionError {
|
|
114
|
+
constructor(message = 'Error al renovar tokens') {
|
|
115
|
+
super(message, 'TOKEN_REFRESH_FAILED', '/session-expired?session=expired');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
class InvalidTokenFormatError extends SessionError {
|
|
119
|
+
constructor(message = 'Formato de token inválido') {
|
|
120
|
+
super(message, 'INVALID_TOKEN_FORMAT', '/?session=invalid');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
297
123
|
|
|
298
124
|
let AuthService = class AuthService {
|
|
299
|
-
|
|
125
|
+
// private networkServices: HMNetworkServices;
|
|
126
|
+
// private jwtManager: JwtManager
|
|
127
|
+
constructor(config, storage, networkServices, jwtManager) {
|
|
300
128
|
this.config = config;
|
|
301
129
|
this.storage = storage;
|
|
130
|
+
this.networkServices = networkServices;
|
|
302
131
|
this.jwtManager = jwtManager;
|
|
303
|
-
this.networkServices = new HMNetworkServices(this.config.ssoBaseUrl);
|
|
132
|
+
// this.networkServices = new HMNetworkServices(this.config.ssoBaseUrl);
|
|
133
|
+
// this.jwtManager = new JwtManager();
|
|
304
134
|
}
|
|
305
135
|
/**
|
|
306
136
|
* Genera los parámetros necesarios para iniciar el login SSO
|
|
@@ -437,7 +267,7 @@ let AuthService = class AuthService {
|
|
|
437
267
|
*/
|
|
438
268
|
async decodeIdToken(idToken) {
|
|
439
269
|
try {
|
|
440
|
-
const decode = this.jwtManager.
|
|
270
|
+
const decode = this.jwtManager.getClaims(idToken);
|
|
441
271
|
if (!decode) {
|
|
442
272
|
return null;
|
|
443
273
|
}
|
|
@@ -484,13 +314,196 @@ let AuthService = class AuthService {
|
|
|
484
314
|
};
|
|
485
315
|
AuthService = __decorate([
|
|
486
316
|
injectable(),
|
|
487
|
-
__metadata("design:paramtypes", [Object,
|
|
317
|
+
__metadata("design:paramtypes", [Object, Object, HMNetworkServices,
|
|
318
|
+
JwtManager])
|
|
488
319
|
], AuthService);
|
|
489
320
|
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
321
|
+
const AUTH_SERVICE_ID = 'AuthService';
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Controller Abstracto Reutilizable
|
|
325
|
+
* Gestiona automáticamente Login, Callback, Me y Logout.
|
|
326
|
+
*/
|
|
327
|
+
let AbstractAuthController = class AbstractAuthController {
|
|
328
|
+
constructor() { }
|
|
329
|
+
async login(req, res) {
|
|
330
|
+
try {
|
|
331
|
+
const autoParam = typeof req.query.auto === 'string' ? req.query.auto : 'false';
|
|
332
|
+
const { loginUrl, tempState } = this.authService.generateLoginParams(autoParam);
|
|
333
|
+
res.cookie('auth_flow', JSON.stringify(tempState), {
|
|
334
|
+
httpOnly: true,
|
|
335
|
+
secure: process.env.NODE_ENV === 'production',
|
|
336
|
+
maxAge: 300000 // 5 min
|
|
337
|
+
});
|
|
338
|
+
res.redirect(loginUrl);
|
|
339
|
+
}
|
|
340
|
+
catch (error) {
|
|
341
|
+
console.error('Login Error:', error);
|
|
342
|
+
res.status(500).send('Login initialization failed');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
async callback(req, res) {
|
|
346
|
+
try {
|
|
347
|
+
const { code, state } = req.query;
|
|
348
|
+
const authFlowCookie = req.cookies['auth_flow'];
|
|
349
|
+
if (!authFlowCookie) {
|
|
350
|
+
res.status(400).send('Missing auth flow cookie');
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const storedState = JSON.parse(authFlowCookie);
|
|
354
|
+
const result = await this.authService.handleCallback(code, state, storedState);
|
|
355
|
+
res.cookie('x-session', result.sessionId, {
|
|
356
|
+
httpOnly: true,
|
|
357
|
+
secure: process.env.NODE_ENV === 'production',
|
|
358
|
+
sameSite: 'lax',
|
|
359
|
+
maxAge: result.expiresIn * 1000,
|
|
360
|
+
path: '/'
|
|
361
|
+
});
|
|
362
|
+
res.clearCookie('auth_flow');
|
|
363
|
+
res.redirect(result.redirectUrl);
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
console.error('Callback Error:', error);
|
|
367
|
+
if (error instanceof HttpError) {
|
|
368
|
+
res.status(error.statusCode).json({
|
|
369
|
+
success: false,
|
|
370
|
+
message: error.message,
|
|
371
|
+
error: error.error
|
|
372
|
+
});
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
res.status(500).json({
|
|
376
|
+
success: false,
|
|
377
|
+
message: 'Failed to complete authentication',
|
|
378
|
+
error: error.message
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
async me(req, res) {
|
|
383
|
+
const sessionId = req.cookies['x-session'];
|
|
384
|
+
if (!sessionId) {
|
|
385
|
+
return res.status(401).json({
|
|
386
|
+
success: false,
|
|
387
|
+
message: 'No session found',
|
|
388
|
+
data: {
|
|
389
|
+
redirect_to: '/?session=required'
|
|
390
|
+
},
|
|
391
|
+
error: {
|
|
392
|
+
message: 'Session is missing',
|
|
393
|
+
code: 'SESSION_MISSING'
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
try {
|
|
398
|
+
const result = await this.authService.getSessionUser(sessionId);
|
|
399
|
+
return res.status(200).json({
|
|
400
|
+
success: true,
|
|
401
|
+
data: result
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
res.clearCookie('x-session', {
|
|
406
|
+
httpOnly: true,
|
|
407
|
+
secure: process.env.NODE_ENV === 'production',
|
|
408
|
+
sameSite: 'lax',
|
|
409
|
+
});
|
|
410
|
+
if (error instanceof SessionError) {
|
|
411
|
+
return res.status(401).json({
|
|
412
|
+
success: false,
|
|
413
|
+
message: error.message,
|
|
414
|
+
data: {
|
|
415
|
+
redirect_to: error.redirectTo || '/login'
|
|
416
|
+
},
|
|
417
|
+
error: {
|
|
418
|
+
message: error.message,
|
|
419
|
+
code: error.code
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
return res.status(500).json({
|
|
425
|
+
success: false,
|
|
426
|
+
message: 'Failed to retrieve session user',
|
|
427
|
+
error: error.message
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async logout(req, res) {
|
|
433
|
+
const sessionId = req.cookies['x-session'];
|
|
434
|
+
if (sessionId) {
|
|
435
|
+
await this.authService.logout(sessionId);
|
|
436
|
+
}
|
|
437
|
+
res.clearCookie('x-session', {
|
|
438
|
+
httpOnly: true,
|
|
439
|
+
secure: process.env.NODE_ENV === 'production',
|
|
440
|
+
sameSite: 'lax',
|
|
441
|
+
});
|
|
442
|
+
return res.status(200).json({ success: true });
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
__decorate([
|
|
446
|
+
inject(AUTH_SERVICE_ID),
|
|
447
|
+
__metadata("design:type", AuthService)
|
|
448
|
+
], AbstractAuthController.prototype, "authService", void 0);
|
|
449
|
+
__decorate([
|
|
450
|
+
Get('/login'),
|
|
451
|
+
__param(0, Req()),
|
|
452
|
+
__param(1, Res()),
|
|
453
|
+
__metadata("design:type", Function),
|
|
454
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
455
|
+
__metadata("design:returntype", Promise)
|
|
456
|
+
], AbstractAuthController.prototype, "login", null);
|
|
457
|
+
__decorate([
|
|
458
|
+
Get('/callback'),
|
|
459
|
+
__metadata("design:type", Function),
|
|
460
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
461
|
+
__metadata("design:returntype", Promise)
|
|
462
|
+
], AbstractAuthController.prototype, "callback", null);
|
|
463
|
+
__decorate([
|
|
464
|
+
Get('/me'),
|
|
465
|
+
__param(0, Req()),
|
|
466
|
+
__param(1, Res()),
|
|
467
|
+
__metadata("design:type", Function),
|
|
468
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
469
|
+
__metadata("design:returntype", Promise)
|
|
470
|
+
], AbstractAuthController.prototype, "me", null);
|
|
471
|
+
__decorate([
|
|
472
|
+
Post('/logout'),
|
|
473
|
+
__param(0, Req()),
|
|
474
|
+
__param(1, Res()),
|
|
475
|
+
__metadata("design:type", Function),
|
|
476
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
477
|
+
__metadata("design:returntype", Promise)
|
|
478
|
+
], AbstractAuthController.prototype, "logout", null);
|
|
479
|
+
AbstractAuthController = __decorate([
|
|
480
|
+
injectable(),
|
|
481
|
+
__metadata("design:paramtypes", [])
|
|
482
|
+
], AbstractAuthController);
|
|
483
|
+
|
|
484
|
+
class AuthCacheAdapter {
|
|
485
|
+
constructor(externalCache) {
|
|
486
|
+
this.externalCache = externalCache;
|
|
487
|
+
}
|
|
488
|
+
async set(key, value, ttlSeconds) {
|
|
489
|
+
await this.externalCache.setObject(key, value, ttlSeconds);
|
|
490
|
+
}
|
|
491
|
+
async get(key) {
|
|
492
|
+
return await this.externalCache.getObject(key);
|
|
493
|
+
}
|
|
494
|
+
async delete(key) {
|
|
495
|
+
await this.externalCache.deleteKey(key);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const registerAuthSdk = (bind, config, cacheFactory) => {
|
|
500
|
+
bind(AUTH_SERVICE_ID).toDynamicValue(async (context) => {
|
|
501
|
+
const rawCache = await Promise.resolve(cacheFactory(context));
|
|
502
|
+
const storageAdapter = new AuthCacheAdapter(rawCache);
|
|
503
|
+
const network = new HMNetworkServices(config.ssoBaseUrl);
|
|
504
|
+
const jwt = new JwtManager();
|
|
505
|
+
return new AuthService(config, storageAdapter, network, jwt);
|
|
493
506
|
}).inSingletonScope();
|
|
494
507
|
};
|
|
495
508
|
|
|
496
|
-
export {
|
|
509
|
+
export { AUTH_SERVICE_ID, AbstractAuthController, AuthService, InvalidTokenFormatError, SessionError, SessionExpiredError, SessionInvalidError, SessionNotFoundError, TokenRefreshFailedError, registerAuthSdk };
|
package/dist/hemia-auth-sdk.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
require('reflect-metadata');
|
|
4
4
|
var common = require('@hemia/common');
|
|
5
5
|
var networkServices = require('@hemia/network-services');
|
|
6
|
+
var jwtManager = require('@hemia/jwt-manager');
|
|
6
7
|
var crypto = require('crypto');
|
|
7
8
|
var inversify = require('inversify');
|
|
8
|
-
var cacheManager = require('@hemia/cache-manager');
|
|
9
9
|
|
|
10
10
|
/******************************************************************************
|
|
11
11
|
Copyright (c) Microsoft Corporation.
|
|
@@ -44,196 +44,6 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
44
44
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
class SessionError extends Error {
|
|
48
|
-
constructor(message, code, redirectTo) {
|
|
49
|
-
super(message);
|
|
50
|
-
this.code = code;
|
|
51
|
-
this.redirectTo = redirectTo;
|
|
52
|
-
this.name = this.constructor.name;
|
|
53
|
-
Error.captureStackTrace(this, this.constructor);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
class SessionNotFoundError extends SessionError {
|
|
57
|
-
constructor(message = 'Sesión no encontrada') {
|
|
58
|
-
super(message, 'SESSION_NOT_FOUND', '/?session=required');
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
class SessionExpiredError extends SessionError {
|
|
62
|
-
constructor(message = 'Sesión expirada') {
|
|
63
|
-
super(message, 'SESSION_EXPIRED', '/session-expired?session=expired');
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
class SessionInvalidError extends SessionError {
|
|
67
|
-
constructor(message = 'Sesión inválida') {
|
|
68
|
-
super(message, 'SESSION_INVALID', '/?session=invalid');
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
class TokenRefreshFailedError extends SessionError {
|
|
72
|
-
constructor(message = 'Error al renovar tokens') {
|
|
73
|
-
super(message, 'TOKEN_REFRESH_FAILED', '/session-expired?session=expired');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
class InvalidTokenFormatError extends SessionError {
|
|
77
|
-
constructor(message = 'Formato de token inválido') {
|
|
78
|
-
super(message, 'INVALID_TOKEN_FORMAT', '/?session=invalid');
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Controller Abstracto Reutilizable
|
|
84
|
-
* Gestiona automáticamente Login, Callback, Me y Logout.
|
|
85
|
-
*/
|
|
86
|
-
class AbstractAuthController {
|
|
87
|
-
constructor(authService) {
|
|
88
|
-
this.authService = authService;
|
|
89
|
-
}
|
|
90
|
-
async login(req, res) {
|
|
91
|
-
try {
|
|
92
|
-
const autoParam = typeof req.query.auto === 'string' ? req.query.auto : 'false';
|
|
93
|
-
const { loginUrl, tempState } = this.authService.generateLoginParams(autoParam);
|
|
94
|
-
res.cookie('auth_flow', JSON.stringify(tempState), {
|
|
95
|
-
httpOnly: true,
|
|
96
|
-
secure: process.env.NODE_ENV === 'production',
|
|
97
|
-
maxAge: 300000 // 5 min
|
|
98
|
-
});
|
|
99
|
-
res.redirect(loginUrl);
|
|
100
|
-
}
|
|
101
|
-
catch (error) {
|
|
102
|
-
console.error('Login Error:', error);
|
|
103
|
-
res.status(500).send('Login initialization failed');
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
async callback(req, res) {
|
|
107
|
-
try {
|
|
108
|
-
const { code, state } = req.query;
|
|
109
|
-
const authFlowCookie = req.cookies['auth_flow'];
|
|
110
|
-
if (!authFlowCookie) {
|
|
111
|
-
res.status(400).send('Missing auth flow cookie');
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
const storedState = JSON.parse(authFlowCookie);
|
|
115
|
-
const result = await this.authService.handleCallback(code, state, storedState);
|
|
116
|
-
res.cookie('x-session', result.sessionId, {
|
|
117
|
-
httpOnly: true,
|
|
118
|
-
secure: process.env.NODE_ENV === 'production',
|
|
119
|
-
sameSite: 'lax',
|
|
120
|
-
maxAge: result.expiresIn * 1000,
|
|
121
|
-
path: '/'
|
|
122
|
-
});
|
|
123
|
-
res.clearCookie('auth_flow');
|
|
124
|
-
res.redirect(result.redirectUrl);
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
console.error('Callback Error:', error);
|
|
128
|
-
if (error instanceof common.HttpError) {
|
|
129
|
-
res.status(error.statusCode).json({
|
|
130
|
-
success: false,
|
|
131
|
-
message: error.message,
|
|
132
|
-
error: error.error
|
|
133
|
-
});
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
res.status(500).json({
|
|
137
|
-
success: false,
|
|
138
|
-
message: 'Failed to complete authentication',
|
|
139
|
-
error: error.message
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
async me(req, res) {
|
|
144
|
-
const sessionId = req.cookies['x-session'];
|
|
145
|
-
if (!sessionId) {
|
|
146
|
-
return res.status(401).json({
|
|
147
|
-
success: false,
|
|
148
|
-
message: 'No session found',
|
|
149
|
-
data: {
|
|
150
|
-
redirect_to: '/?session=required'
|
|
151
|
-
},
|
|
152
|
-
error: {
|
|
153
|
-
message: 'Session is missing',
|
|
154
|
-
code: 'SESSION_MISSING'
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
try {
|
|
159
|
-
const result = await this.authService.getSessionUser(sessionId);
|
|
160
|
-
return res.status(200).json({
|
|
161
|
-
success: true,
|
|
162
|
-
data: result
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
catch (error) {
|
|
166
|
-
res.clearCookie('x-session', {
|
|
167
|
-
httpOnly: true,
|
|
168
|
-
secure: process.env.NODE_ENV === 'production',
|
|
169
|
-
sameSite: 'lax',
|
|
170
|
-
});
|
|
171
|
-
if (error instanceof SessionError) {
|
|
172
|
-
return res.status(401).json({
|
|
173
|
-
success: false,
|
|
174
|
-
message: error.message,
|
|
175
|
-
data: {
|
|
176
|
-
redirect_to: error.redirectTo || '/login'
|
|
177
|
-
},
|
|
178
|
-
error: {
|
|
179
|
-
message: error.message,
|
|
180
|
-
code: error.code
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
return res.status(500).json({
|
|
186
|
-
success: false,
|
|
187
|
-
message: 'Failed to retrieve session user',
|
|
188
|
-
error: error.message
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
async logout(req, res) {
|
|
194
|
-
const sessionId = req.cookies['x-session'];
|
|
195
|
-
if (sessionId) {
|
|
196
|
-
await this.authService.logout(sessionId);
|
|
197
|
-
}
|
|
198
|
-
res.clearCookie('x-session', {
|
|
199
|
-
httpOnly: true,
|
|
200
|
-
secure: process.env.NODE_ENV === 'production',
|
|
201
|
-
sameSite: 'lax',
|
|
202
|
-
});
|
|
203
|
-
return res.status(200).json({ success: true });
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
__decorate([
|
|
207
|
-
common.Get('/login'),
|
|
208
|
-
__param(0, common.Req()),
|
|
209
|
-
__param(1, common.Res()),
|
|
210
|
-
__metadata("design:type", Function),
|
|
211
|
-
__metadata("design:paramtypes", [Object, Object]),
|
|
212
|
-
__metadata("design:returntype", Promise)
|
|
213
|
-
], AbstractAuthController.prototype, "login", null);
|
|
214
|
-
__decorate([
|
|
215
|
-
common.Get('/callback'),
|
|
216
|
-
__metadata("design:type", Function),
|
|
217
|
-
__metadata("design:paramtypes", [Object, Object]),
|
|
218
|
-
__metadata("design:returntype", Promise)
|
|
219
|
-
], AbstractAuthController.prototype, "callback", null);
|
|
220
|
-
__decorate([
|
|
221
|
-
common.Get('/me'),
|
|
222
|
-
__param(0, common.Req()),
|
|
223
|
-
__param(1, common.Res()),
|
|
224
|
-
__metadata("design:type", Function),
|
|
225
|
-
__metadata("design:paramtypes", [Object, Object]),
|
|
226
|
-
__metadata("design:returntype", Promise)
|
|
227
|
-
], AbstractAuthController.prototype, "me", null);
|
|
228
|
-
__decorate([
|
|
229
|
-
common.Post('/logout'),
|
|
230
|
-
__param(0, common.Req()),
|
|
231
|
-
__param(1, common.Res()),
|
|
232
|
-
__metadata("design:type", Function),
|
|
233
|
-
__metadata("design:paramtypes", [Object, Object]),
|
|
234
|
-
__metadata("design:returntype", Promise)
|
|
235
|
-
], AbstractAuthController.prototype, "logout", null);
|
|
236
|
-
|
|
237
47
|
/**
|
|
238
48
|
* Utilidades para manejo de PKCE y codificación Base64URL
|
|
239
49
|
*/
|
|
@@ -278,31 +88,51 @@ class Generators {
|
|
|
278
88
|
}
|
|
279
89
|
}
|
|
280
90
|
|
|
281
|
-
|
|
282
|
-
constructor(
|
|
283
|
-
|
|
91
|
+
class SessionError extends Error {
|
|
92
|
+
constructor(message, code, redirectTo) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.code = code;
|
|
95
|
+
this.redirectTo = redirectTo;
|
|
96
|
+
this.name = this.constructor.name;
|
|
97
|
+
Error.captureStackTrace(this, this.constructor);
|
|
284
98
|
}
|
|
285
|
-
|
|
286
|
-
|
|
99
|
+
}
|
|
100
|
+
class SessionNotFoundError extends SessionError {
|
|
101
|
+
constructor(message = 'Sesión no encontrada') {
|
|
102
|
+
super(message, 'SESSION_NOT_FOUND', '/?session=required');
|
|
287
103
|
}
|
|
288
|
-
|
|
289
|
-
|
|
104
|
+
}
|
|
105
|
+
class SessionExpiredError extends SessionError {
|
|
106
|
+
constructor(message = 'Sesión expirada') {
|
|
107
|
+
super(message, 'SESSION_EXPIRED', '/session-expired?session=expired');
|
|
290
108
|
}
|
|
291
|
-
|
|
292
|
-
|
|
109
|
+
}
|
|
110
|
+
class SessionInvalidError extends SessionError {
|
|
111
|
+
constructor(message = 'Sesión inválida') {
|
|
112
|
+
super(message, 'SESSION_INVALID', '/?session=invalid');
|
|
293
113
|
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
114
|
+
}
|
|
115
|
+
class TokenRefreshFailedError extends SessionError {
|
|
116
|
+
constructor(message = 'Error al renovar tokens') {
|
|
117
|
+
super(message, 'TOKEN_REFRESH_FAILED', '/session-expired?session=expired');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
class InvalidTokenFormatError extends SessionError {
|
|
121
|
+
constructor(message = 'Formato de token inválido') {
|
|
122
|
+
super(message, 'INVALID_TOKEN_FORMAT', '/?session=invalid');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
299
125
|
|
|
300
126
|
exports.AuthService = class AuthService {
|
|
301
|
-
|
|
127
|
+
// private networkServices: HMNetworkServices;
|
|
128
|
+
// private jwtManager: JwtManager
|
|
129
|
+
constructor(config, storage, networkServices, jwtManager) {
|
|
302
130
|
this.config = config;
|
|
303
131
|
this.storage = storage;
|
|
132
|
+
this.networkServices = networkServices;
|
|
304
133
|
this.jwtManager = jwtManager;
|
|
305
|
-
this.networkServices = new
|
|
134
|
+
// this.networkServices = new HMNetworkServices(this.config.ssoBaseUrl);
|
|
135
|
+
// this.jwtManager = new JwtManager();
|
|
306
136
|
}
|
|
307
137
|
/**
|
|
308
138
|
* Genera los parámetros necesarios para iniciar el login SSO
|
|
@@ -439,7 +269,7 @@ exports.AuthService = class AuthService {
|
|
|
439
269
|
*/
|
|
440
270
|
async decodeIdToken(idToken) {
|
|
441
271
|
try {
|
|
442
|
-
const decode = this.jwtManager.
|
|
272
|
+
const decode = this.jwtManager.getClaims(idToken);
|
|
443
273
|
if (!decode) {
|
|
444
274
|
return null;
|
|
445
275
|
}
|
|
@@ -486,16 +316,199 @@ exports.AuthService = class AuthService {
|
|
|
486
316
|
};
|
|
487
317
|
exports.AuthService = __decorate([
|
|
488
318
|
inversify.injectable(),
|
|
489
|
-
__metadata("design:paramtypes", [Object,
|
|
319
|
+
__metadata("design:paramtypes", [Object, Object, networkServices.HMNetworkServices,
|
|
320
|
+
jwtManager.JwtManager])
|
|
490
321
|
], exports.AuthService);
|
|
491
322
|
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
323
|
+
const AUTH_SERVICE_ID = 'AuthService';
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Controller Abstracto Reutilizable
|
|
327
|
+
* Gestiona automáticamente Login, Callback, Me y Logout.
|
|
328
|
+
*/
|
|
329
|
+
exports.AbstractAuthController = class AbstractAuthController {
|
|
330
|
+
constructor() { }
|
|
331
|
+
async login(req, res) {
|
|
332
|
+
try {
|
|
333
|
+
const autoParam = typeof req.query.auto === 'string' ? req.query.auto : 'false';
|
|
334
|
+
const { loginUrl, tempState } = this.authService.generateLoginParams(autoParam);
|
|
335
|
+
res.cookie('auth_flow', JSON.stringify(tempState), {
|
|
336
|
+
httpOnly: true,
|
|
337
|
+
secure: process.env.NODE_ENV === 'production',
|
|
338
|
+
maxAge: 300000 // 5 min
|
|
339
|
+
});
|
|
340
|
+
res.redirect(loginUrl);
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
console.error('Login Error:', error);
|
|
344
|
+
res.status(500).send('Login initialization failed');
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
async callback(req, res) {
|
|
348
|
+
try {
|
|
349
|
+
const { code, state } = req.query;
|
|
350
|
+
const authFlowCookie = req.cookies['auth_flow'];
|
|
351
|
+
if (!authFlowCookie) {
|
|
352
|
+
res.status(400).send('Missing auth flow cookie');
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const storedState = JSON.parse(authFlowCookie);
|
|
356
|
+
const result = await this.authService.handleCallback(code, state, storedState);
|
|
357
|
+
res.cookie('x-session', result.sessionId, {
|
|
358
|
+
httpOnly: true,
|
|
359
|
+
secure: process.env.NODE_ENV === 'production',
|
|
360
|
+
sameSite: 'lax',
|
|
361
|
+
maxAge: result.expiresIn * 1000,
|
|
362
|
+
path: '/'
|
|
363
|
+
});
|
|
364
|
+
res.clearCookie('auth_flow');
|
|
365
|
+
res.redirect(result.redirectUrl);
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
console.error('Callback Error:', error);
|
|
369
|
+
if (error instanceof common.HttpError) {
|
|
370
|
+
res.status(error.statusCode).json({
|
|
371
|
+
success: false,
|
|
372
|
+
message: error.message,
|
|
373
|
+
error: error.error
|
|
374
|
+
});
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
res.status(500).json({
|
|
378
|
+
success: false,
|
|
379
|
+
message: 'Failed to complete authentication',
|
|
380
|
+
error: error.message
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
async me(req, res) {
|
|
385
|
+
const sessionId = req.cookies['x-session'];
|
|
386
|
+
if (!sessionId) {
|
|
387
|
+
return res.status(401).json({
|
|
388
|
+
success: false,
|
|
389
|
+
message: 'No session found',
|
|
390
|
+
data: {
|
|
391
|
+
redirect_to: '/?session=required'
|
|
392
|
+
},
|
|
393
|
+
error: {
|
|
394
|
+
message: 'Session is missing',
|
|
395
|
+
code: 'SESSION_MISSING'
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
try {
|
|
400
|
+
const result = await this.authService.getSessionUser(sessionId);
|
|
401
|
+
return res.status(200).json({
|
|
402
|
+
success: true,
|
|
403
|
+
data: result
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
res.clearCookie('x-session', {
|
|
408
|
+
httpOnly: true,
|
|
409
|
+
secure: process.env.NODE_ENV === 'production',
|
|
410
|
+
sameSite: 'lax',
|
|
411
|
+
});
|
|
412
|
+
if (error instanceof SessionError) {
|
|
413
|
+
return res.status(401).json({
|
|
414
|
+
success: false,
|
|
415
|
+
message: error.message,
|
|
416
|
+
data: {
|
|
417
|
+
redirect_to: error.redirectTo || '/login'
|
|
418
|
+
},
|
|
419
|
+
error: {
|
|
420
|
+
message: error.message,
|
|
421
|
+
code: error.code
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
return res.status(500).json({
|
|
427
|
+
success: false,
|
|
428
|
+
message: 'Failed to retrieve session user',
|
|
429
|
+
error: error.message
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
async logout(req, res) {
|
|
435
|
+
const sessionId = req.cookies['x-session'];
|
|
436
|
+
if (sessionId) {
|
|
437
|
+
await this.authService.logout(sessionId);
|
|
438
|
+
}
|
|
439
|
+
res.clearCookie('x-session', {
|
|
440
|
+
httpOnly: true,
|
|
441
|
+
secure: process.env.NODE_ENV === 'production',
|
|
442
|
+
sameSite: 'lax',
|
|
443
|
+
});
|
|
444
|
+
return res.status(200).json({ success: true });
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
__decorate([
|
|
448
|
+
inversify.inject(AUTH_SERVICE_ID),
|
|
449
|
+
__metadata("design:type", exports.AuthService)
|
|
450
|
+
], exports.AbstractAuthController.prototype, "authService", void 0);
|
|
451
|
+
__decorate([
|
|
452
|
+
common.Get('/login'),
|
|
453
|
+
__param(0, common.Req()),
|
|
454
|
+
__param(1, common.Res()),
|
|
455
|
+
__metadata("design:type", Function),
|
|
456
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
457
|
+
__metadata("design:returntype", Promise)
|
|
458
|
+
], exports.AbstractAuthController.prototype, "login", null);
|
|
459
|
+
__decorate([
|
|
460
|
+
common.Get('/callback'),
|
|
461
|
+
__metadata("design:type", Function),
|
|
462
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
463
|
+
__metadata("design:returntype", Promise)
|
|
464
|
+
], exports.AbstractAuthController.prototype, "callback", null);
|
|
465
|
+
__decorate([
|
|
466
|
+
common.Get('/me'),
|
|
467
|
+
__param(0, common.Req()),
|
|
468
|
+
__param(1, common.Res()),
|
|
469
|
+
__metadata("design:type", Function),
|
|
470
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
471
|
+
__metadata("design:returntype", Promise)
|
|
472
|
+
], exports.AbstractAuthController.prototype, "me", null);
|
|
473
|
+
__decorate([
|
|
474
|
+
common.Post('/logout'),
|
|
475
|
+
__param(0, common.Req()),
|
|
476
|
+
__param(1, common.Res()),
|
|
477
|
+
__metadata("design:type", Function),
|
|
478
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
479
|
+
__metadata("design:returntype", Promise)
|
|
480
|
+
], exports.AbstractAuthController.prototype, "logout", null);
|
|
481
|
+
exports.AbstractAuthController = __decorate([
|
|
482
|
+
inversify.injectable(),
|
|
483
|
+
__metadata("design:paramtypes", [])
|
|
484
|
+
], exports.AbstractAuthController);
|
|
485
|
+
|
|
486
|
+
class AuthCacheAdapter {
|
|
487
|
+
constructor(externalCache) {
|
|
488
|
+
this.externalCache = externalCache;
|
|
489
|
+
}
|
|
490
|
+
async set(key, value, ttlSeconds) {
|
|
491
|
+
await this.externalCache.setObject(key, value, ttlSeconds);
|
|
492
|
+
}
|
|
493
|
+
async get(key) {
|
|
494
|
+
return await this.externalCache.getObject(key);
|
|
495
|
+
}
|
|
496
|
+
async delete(key) {
|
|
497
|
+
await this.externalCache.deleteKey(key);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const registerAuthSdk = (bind, config, cacheFactory) => {
|
|
502
|
+
bind(AUTH_SERVICE_ID).toDynamicValue(async (context) => {
|
|
503
|
+
const rawCache = await Promise.resolve(cacheFactory(context));
|
|
504
|
+
const storageAdapter = new AuthCacheAdapter(rawCache);
|
|
505
|
+
const network = new networkServices.HMNetworkServices(config.ssoBaseUrl);
|
|
506
|
+
const jwt = new jwtManager.JwtManager();
|
|
507
|
+
return new exports.AuthService(config, storageAdapter, network, jwt);
|
|
495
508
|
}).inSingletonScope();
|
|
496
509
|
};
|
|
497
510
|
|
|
498
|
-
exports.
|
|
511
|
+
exports.AUTH_SERVICE_ID = AUTH_SERVICE_ID;
|
|
499
512
|
exports.InvalidTokenFormatError = InvalidTokenFormatError;
|
|
500
513
|
exports.SessionError = SessionError;
|
|
501
514
|
exports.SessionExpiredError = SessionExpiredError;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./internal.adapter";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ISessionStorage } from "../types";
|
|
2
|
+
export interface IHemiaCacheService {
|
|
3
|
+
setObject<T>(key: string, value: T, expireTime?: number): Promise<void>;
|
|
4
|
+
getObject<T>(key: string): Promise<T | null>;
|
|
5
|
+
deleteKey(key: string): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare class AuthCacheAdapter implements ISessionStorage {
|
|
8
|
+
private externalCache;
|
|
9
|
+
constructor(externalCache: IHemiaCacheService);
|
|
10
|
+
set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
|
|
11
|
+
get<T>(key: string): Promise<T | null>;
|
|
12
|
+
delete(key: string): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const AUTH_SERVICE_ID = "AuthService";
|
|
@@ -6,7 +6,7 @@ import { AuthService } from "../services/auth.service";
|
|
|
6
6
|
*/
|
|
7
7
|
export declare abstract class AbstractAuthController {
|
|
8
8
|
protected readonly authService: AuthService;
|
|
9
|
-
protected constructor(
|
|
9
|
+
protected constructor();
|
|
10
10
|
login(req: Request, res: Response): Promise<void>;
|
|
11
11
|
callback(req: Request, res: Response): Promise<void>;
|
|
12
12
|
me(req: Request, res: Response): Promise<Response>;
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/ioc.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { IAuthConfig
|
|
3
|
-
import {
|
|
4
|
-
export
|
|
1
|
+
import { Bind, ResolutionContext } from "inversify";
|
|
2
|
+
import { IAuthConfig } from "./types";
|
|
3
|
+
import { IHemiaCacheService } from "./adapters";
|
|
4
|
+
export type CacheFactory = (context: ResolutionContext) => Promise<IHemiaCacheService> | IHemiaCacheService;
|
|
5
|
+
export declare const registerAuthSdk: (bind: Bind, config: IAuthConfig, cacheFactory: CacheFactory) => void;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { HMNetworkServices } from '@hemia/network-services';
|
|
2
|
+
import { JwtManager } from '@hemia/jwt-manager';
|
|
3
|
+
import { IAuthConfig, ICallbackResponse, ILoginParams, ISessionStorage, ISessionUser, IStoredState } from '../types';
|
|
3
4
|
export declare class AuthService {
|
|
4
|
-
private config;
|
|
5
|
-
private storage;
|
|
6
|
-
private
|
|
7
|
-
private
|
|
8
|
-
constructor(config: IAuthConfig, storage:
|
|
5
|
+
private readonly config;
|
|
6
|
+
private readonly storage;
|
|
7
|
+
private readonly networkServices;
|
|
8
|
+
private readonly jwtManager;
|
|
9
|
+
constructor(config: IAuthConfig, storage: ISessionStorage, networkServices: HMNetworkServices, jwtManager: JwtManager);
|
|
9
10
|
/**
|
|
10
11
|
* Genera los parámetros necesarios para iniciar el login SSO
|
|
11
12
|
* @param auto
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hemia/auth-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Hemia SDK for authentication",
|
|
5
5
|
"main": "dist/hemia-auth-sdk.js",
|
|
6
6
|
"module": "dist/hemia-auth-sdk.esm.js",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"@hemia/network-services": "^0.0.3",
|
|
24
24
|
"@hemia/common": "^0.0.2",
|
|
25
25
|
"@hemia/cache-manager": "^0.0.5",
|
|
26
|
+
"@hemia/jwt-manager": "^0.0.4",
|
|
26
27
|
"@types/express": "^4.17.21",
|
|
27
28
|
"express": "^5.2.1",
|
|
28
29
|
"events": "^3.3.0",
|
|
@@ -45,9 +46,10 @@
|
|
|
45
46
|
"inversify": "^7.11.0",
|
|
46
47
|
"@hemia/common": "^0.0.2",
|
|
47
48
|
"@hemia/network-services": "^0.0.3",
|
|
48
|
-
"@hemia/cache-manager": "^0.0.5"
|
|
49
|
+
"@hemia/cache-manager": "^0.0.5",
|
|
50
|
+
"@hemia/jwt-manager": "^0.0.4"
|
|
49
51
|
},
|
|
50
52
|
"dependencies": {
|
|
51
|
-
|
|
53
|
+
|
|
52
54
|
}
|
|
53
55
|
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { CacheService as CacheServiceClient } from "@hemia/cache-manager";
|
|
2
|
-
export declare class AuthCacheService {
|
|
3
|
-
private cacheClient;
|
|
4
|
-
constructor(cacheClient: CacheServiceClient);
|
|
5
|
-
set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
|
|
6
|
-
get<T>(key: string): Promise<T | null>;
|
|
7
|
-
delete(key: string): Promise<void>;
|
|
8
|
-
}
|