@nik2208/node-auth 1.0.2

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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +636 -0
  3. package/dist/abstract/base-auth-strategy.abstract.d.ts +7 -0
  4. package/dist/abstract/base-auth-strategy.abstract.d.ts.map +1 -0
  5. package/dist/abstract/base-auth-strategy.abstract.js +7 -0
  6. package/dist/abstract/base-auth-strategy.abstract.js.map +1 -0
  7. package/dist/abstract/base-oauth-strategy.abstract.d.ts +26 -0
  8. package/dist/abstract/base-oauth-strategy.abstract.d.ts.map +1 -0
  9. package/dist/abstract/base-oauth-strategy.abstract.js +11 -0
  10. package/dist/abstract/base-oauth-strategy.abstract.js.map +1 -0
  11. package/dist/auth-configurator.d.ts +24 -0
  12. package/dist/auth-configurator.d.ts.map +1 -0
  13. package/dist/auth-configurator.js +42 -0
  14. package/dist/auth-configurator.js.map +1 -0
  15. package/dist/index.d.ts +25 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +36 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/interfaces/auth-strategy.interface.d.ts +6 -0
  20. package/dist/interfaces/auth-strategy.interface.d.ts.map +1 -0
  21. package/dist/interfaces/auth-strategy.interface.js +3 -0
  22. package/dist/interfaces/auth-strategy.interface.js.map +1 -0
  23. package/dist/interfaces/token-store.interface.d.ts +10 -0
  24. package/dist/interfaces/token-store.interface.d.ts.map +1 -0
  25. package/dist/interfaces/token-store.interface.js +3 -0
  26. package/dist/interfaces/token-store.interface.js.map +1 -0
  27. package/dist/interfaces/user-store.interface.d.ts +23 -0
  28. package/dist/interfaces/user-store.interface.d.ts.map +1 -0
  29. package/dist/interfaces/user-store.interface.js +3 -0
  30. package/dist/interfaces/user-store.interface.js.map +1 -0
  31. package/dist/middleware/auth.middleware.d.ts +12 -0
  32. package/dist/middleware/auth.middleware.d.ts.map +1 -0
  33. package/dist/middleware/auth.middleware.js +23 -0
  34. package/dist/middleware/auth.middleware.js.map +1 -0
  35. package/dist/models/auth-config.model.d.ts +96 -0
  36. package/dist/models/auth-config.model.d.ts.map +1 -0
  37. package/dist/models/auth-config.model.js +3 -0
  38. package/dist/models/auth-config.model.js.map +1 -0
  39. package/dist/models/errors.d.ts +6 -0
  40. package/dist/models/errors.d.ts.map +1 -0
  41. package/dist/models/errors.js +13 -0
  42. package/dist/models/errors.js.map +1 -0
  43. package/dist/models/token.model.d.ts +12 -0
  44. package/dist/models/token.model.d.ts.map +1 -0
  45. package/dist/models/token.model.js +3 -0
  46. package/dist/models/token.model.js.map +1 -0
  47. package/dist/models/user.model.d.ts +18 -0
  48. package/dist/models/user.model.d.ts.map +1 -0
  49. package/dist/models/user.model.js +3 -0
  50. package/dist/models/user.model.js.map +1 -0
  51. package/dist/router/auth.router.d.ts +13 -0
  52. package/dist/router/auth.router.d.ts.map +1 -0
  53. package/dist/router/auth.router.js +329 -0
  54. package/dist/router/auth.router.js.map +1 -0
  55. package/dist/services/mailer.service.d.ts +11 -0
  56. package/dist/services/mailer.service.d.ts.map +1 -0
  57. package/dist/services/mailer.service.js +138 -0
  58. package/dist/services/mailer.service.js.map +1 -0
  59. package/dist/services/password.service.d.ts +5 -0
  60. package/dist/services/password.service.d.ts.map +1 -0
  61. package/dist/services/password.service.js +17 -0
  62. package/dist/services/password.service.js.map +1 -0
  63. package/dist/services/sms.service.d.ts +14 -0
  64. package/dist/services/sms.service.d.ts.map +1 -0
  65. package/dist/services/sms.service.js +51 -0
  66. package/dist/services/sms.service.js.map +1 -0
  67. package/dist/services/token.service.d.ts +13 -0
  68. package/dist/services/token.service.d.ts.map +1 -0
  69. package/dist/services/token.service.js +78 -0
  70. package/dist/services/token.service.js.map +1 -0
  71. package/dist/strategies/local/local.strategy.d.ts +19 -0
  72. package/dist/strategies/local/local.strategy.d.ts.map +1 -0
  73. package/dist/strategies/local/local.strategy.js +29 -0
  74. package/dist/strategies/local/local.strategy.js.map +1 -0
  75. package/dist/strategies/magic-link/magic-link.strategy.d.ts +8 -0
  76. package/dist/strategies/magic-link/magic-link.strategy.d.ts.map +1 -0
  77. package/dist/strategies/magic-link/magic-link.strategy.js +50 -0
  78. package/dist/strategies/magic-link/magic-link.strategy.js.map +1 -0
  79. package/dist/strategies/oauth/github.strategy.d.ts +29 -0
  80. package/dist/strategies/oauth/github.strategy.d.ts.map +1 -0
  81. package/dist/strategies/oauth/github.strategy.js +69 -0
  82. package/dist/strategies/oauth/github.strategy.js.map +1 -0
  83. package/dist/strategies/oauth/google.strategy.d.ts +29 -0
  84. package/dist/strategies/oauth/google.strategy.d.ts.map +1 -0
  85. package/dist/strategies/oauth/google.strategy.js +61 -0
  86. package/dist/strategies/oauth/google.strategy.js.map +1 -0
  87. package/dist/strategies/sms/sms.strategy.d.ts +7 -0
  88. package/dist/strategies/sms/sms.strategy.d.ts.map +1 -0
  89. package/dist/strategies/sms/sms.strategy.js +39 -0
  90. package/dist/strategies/sms/sms.strategy.js.map +1 -0
  91. package/dist/strategies/two-factor/totp.strategy.d.ts +12 -0
  92. package/dist/strategies/two-factor/totp.strategy.d.ts.map +1 -0
  93. package/dist/strategies/two-factor/totp.strategy.js +32 -0
  94. package/dist/strategies/two-factor/totp.strategy.js.map +1 -0
  95. package/package.json +48 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.service.d.ts","sourceRoot":"","sources":["../../src/services/token.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAGzD,qBAAa,YAAY;IACvB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS;IAe7E,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,kBAAkB;IASxE,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,kBAAkB;IASzE,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAkB3E,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI;IAKtC,mBAAmB,CAAC,KAAK,GAAE,MAAW,GAAG,MAAM;IAI/C,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAexE"}
@@ -0,0 +1,78 @@
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.TokenService = void 0;
7
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ const errors_1 = require("../models/errors");
10
+ class TokenService {
11
+ generateTokenPair(payload, config) {
12
+ const { sub, email, role } = payload;
13
+ const accessToken = jsonwebtoken_1.default.sign({ sub, email, role }, config.accessTokenSecret, { expiresIn: config.accessTokenExpiresIn ?? '15m' });
14
+ const refreshToken = jsonwebtoken_1.default.sign({ sub, email, role }, config.refreshTokenSecret, { expiresIn: config.refreshTokenExpiresIn ?? '7d' });
15
+ return { accessToken, refreshToken };
16
+ }
17
+ verifyAccessToken(token, config) {
18
+ try {
19
+ const payload = jsonwebtoken_1.default.verify(token, config.accessTokenSecret);
20
+ return payload;
21
+ }
22
+ catch {
23
+ throw new errors_1.AuthError('Invalid or expired access token', 'INVALID_ACCESS_TOKEN', 401);
24
+ }
25
+ }
26
+ verifyRefreshToken(token, config) {
27
+ try {
28
+ const payload = jsonwebtoken_1.default.verify(token, config.refreshTokenSecret);
29
+ return payload;
30
+ }
31
+ catch {
32
+ throw new errors_1.AuthError('Invalid or expired refresh token', 'INVALID_REFRESH_TOKEN', 401);
33
+ }
34
+ }
35
+ setTokenCookies(res, tokens, config) {
36
+ const cookieOpts = {
37
+ httpOnly: true,
38
+ secure: config.cookieOptions?.secure ?? false,
39
+ sameSite: (config.cookieOptions?.sameSite ?? 'lax'),
40
+ domain: config.cookieOptions?.domain,
41
+ };
42
+ res.cookie('accessToken', tokens.accessToken, {
43
+ ...cookieOpts,
44
+ maxAge: 15 * 60 * 1000,
45
+ });
46
+ res.cookie('refreshToken', tokens.refreshToken, {
47
+ ...cookieOpts,
48
+ maxAge: 7 * 24 * 60 * 60 * 1000,
49
+ path: '/auth/refresh',
50
+ });
51
+ }
52
+ clearTokenCookies(res) {
53
+ res.clearCookie('accessToken');
54
+ res.clearCookie('refreshToken', { path: '/auth/refresh' });
55
+ }
56
+ generateSecureToken(bytes = 32) {
57
+ return crypto_1.default.randomBytes(bytes).toString('hex');
58
+ }
59
+ extractTokenFromCookie(req, cookieName) {
60
+ // First try cookie-parser parsed cookies
61
+ if (req.cookies && req.cookies[cookieName]) {
62
+ return req.cookies[cookieName];
63
+ }
64
+ // Fallback: parse raw Cookie header
65
+ const cookieHeader = req.headers?.cookie;
66
+ if (!cookieHeader)
67
+ return null;
68
+ const cookies = cookieHeader.split(';').reduce((acc, part) => {
69
+ const [key, ...val] = part.trim().split('=');
70
+ if (key)
71
+ acc[key.trim()] = decodeURIComponent(val.join('='));
72
+ return acc;
73
+ }, {});
74
+ return cookies[cookieName] ?? null;
75
+ }
76
+ }
77
+ exports.TokenService = TokenService;
78
+ //# sourceMappingURL=token.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.service.js","sourceRoot":"","sources":["../../src/services/token.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { BaseAuthStrategy } from '../../abstract/base-auth-strategy.abstract';
2
+ import { AuthConfig } from '../../models/auth-config.model';
3
+ import { BaseUser } from '../../models/user.model';
4
+ import { IUserStore } from '../../interfaces/user-store.interface';
5
+ import { PasswordService } from '../../services/password.service';
6
+ export declare class LocalStrategy extends BaseAuthStrategy<{
7
+ email: string;
8
+ password: string;
9
+ }, BaseUser> {
10
+ private readonly userStore;
11
+ private readonly passwordService;
12
+ name: string;
13
+ constructor(userStore: IUserStore, passwordService: PasswordService);
14
+ authenticate(input: {
15
+ email: string;
16
+ password: string;
17
+ }, _config: AuthConfig): Promise<BaseUser>;
18
+ }
19
+ //# sourceMappingURL=local.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/local/local.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGlE,qBAAa,aAAc,SAAQ,gBAAgB,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ,CAAC;IAI9F,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAJlC,IAAI,SAAW;gBAGI,SAAS,EAAE,UAAU,EACrB,eAAe,EAAE,eAAe;IAK7C,YAAY,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;CAcvG"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalStrategy = void 0;
4
+ const base_auth_strategy_abstract_1 = require("../../abstract/base-auth-strategy.abstract");
5
+ const errors_1 = require("../../models/errors");
6
+ class LocalStrategy extends base_auth_strategy_abstract_1.BaseAuthStrategy {
7
+ constructor(userStore, passwordService) {
8
+ super();
9
+ this.userStore = userStore;
10
+ this.passwordService = passwordService;
11
+ this.name = 'local';
12
+ }
13
+ async authenticate(input, _config) {
14
+ const user = await this.userStore.findByEmail(input.email);
15
+ if (!user) {
16
+ throw new errors_1.AuthError('Invalid credentials', 'INVALID_CREDENTIALS', 401);
17
+ }
18
+ if (!user.password) {
19
+ throw new errors_1.AuthError('Invalid credentials', 'INVALID_CREDENTIALS', 401);
20
+ }
21
+ const valid = await this.passwordService.compare(input.password, user.password);
22
+ if (!valid) {
23
+ throw new errors_1.AuthError('Invalid credentials', 'INVALID_CREDENTIALS', 401);
24
+ }
25
+ return user;
26
+ }
27
+ }
28
+ exports.LocalStrategy = LocalStrategy;
29
+ //# sourceMappingURL=local.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.strategy.js","sourceRoot":"","sources":["../../../src/strategies/local/local.strategy.ts"],"names":[],"mappings":";;;AAAA,4FAA8E;AAK9E,gDAAgD;AAEhD,MAAa,aAAc,SAAQ,8CAA+D;IAGhG,YACmB,SAAqB,EACrB,eAAgC;QAEjD,KAAK,EAAE,CAAC;QAHS,cAAS,GAAT,SAAS,CAAY;QACrB,oBAAe,GAAf,eAAe,CAAiB;QAJnD,SAAI,GAAG,OAAO,CAAC;IAOf,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAA0C,EAAE,OAAmB;QAChF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,kBAAS,CAAC,qBAAqB,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,kBAAS,CAAC,qBAAqB,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,kBAAS,CAAC,qBAAqB,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAxBD,sCAwBC"}
@@ -0,0 +1,8 @@
1
+ import { IUserStore } from '../../interfaces/user-store.interface';
2
+ import { AuthConfig } from '../../models/auth-config.model';
3
+ import { BaseUser } from '../../models/user.model';
4
+ export declare class MagicLinkStrategy {
5
+ sendMagicLink(email: string, userStore: IUserStore, config: AuthConfig, lang?: string): Promise<void>;
6
+ verify(token: string, userStore: IUserStore): Promise<BaseUser>;
7
+ }
8
+ //# sourceMappingURL=magic-link.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"magic-link.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/magic-link/magic-link.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAOnD,qBAAa,iBAAiB;IACtB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBrG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;CAiBtE"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MagicLinkStrategy = void 0;
4
+ const token_service_1 = require("../../services/token.service");
5
+ const mailer_service_1 = require("../../services/mailer.service");
6
+ const errors_1 = require("../../models/errors");
7
+ const tokenService = new token_service_1.TokenService();
8
+ class MagicLinkStrategy {
9
+ async sendMagicLink(email, userStore, config, lang) {
10
+ if (!config.email?.sendMagicLink && !config.email?.mailer) {
11
+ throw new errors_1.AuthError('Email not configured', 'EMAIL_NOT_CONFIGURED', 500);
12
+ }
13
+ const user = await userStore.findByEmail(email);
14
+ if (!user) {
15
+ // Don't reveal whether email exists
16
+ return;
17
+ }
18
+ const token = tokenService.generateSecureToken();
19
+ const expiry = new Date(Date.now() + 15 * 60 * 1000); // 15 min
20
+ await userStore.updateMagicLinkToken(user.id, token, expiry);
21
+ const siteUrl = config.email?.siteUrl ?? '';
22
+ const link = `${siteUrl}/auth/magic-link/verify?token=${token}`;
23
+ if (config.email?.sendMagicLink) {
24
+ await config.email.sendMagicLink(email, token, link, lang);
25
+ }
26
+ else if (config.email?.mailer) {
27
+ const mailer = new mailer_service_1.MailerService(config.email.mailer);
28
+ await mailer.sendMagicLink(email, token, link, lang);
29
+ }
30
+ }
31
+ async verify(token, userStore) {
32
+ if (!userStore.findByMagicLinkToken) {
33
+ throw new errors_1.AuthError('UserStore does not implement findByMagicLinkToken', 'NOT_IMPLEMENTED', 500);
34
+ }
35
+ const user = await userStore.findByMagicLinkToken(token);
36
+ if (!user) {
37
+ throw new errors_1.AuthError('Invalid magic link token', 'INVALID_MAGIC_LINK', 401);
38
+ }
39
+ if (!user.magicLinkToken || user.magicLinkToken !== token) {
40
+ throw new errors_1.AuthError('Invalid magic link token', 'INVALID_MAGIC_LINK', 401);
41
+ }
42
+ if (user.magicLinkTokenExpiry && new Date() > user.magicLinkTokenExpiry) {
43
+ throw new errors_1.AuthError('Magic link token has expired', 'MAGIC_LINK_EXPIRED', 401);
44
+ }
45
+ await userStore.updateMagicLinkToken(user.id, null, null);
46
+ return user;
47
+ }
48
+ }
49
+ exports.MagicLinkStrategy = MagicLinkStrategy;
50
+ //# sourceMappingURL=magic-link.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"magic-link.strategy.js","sourceRoot":"","sources":["../../../src/strategies/magic-link/magic-link.strategy.ts"],"names":[],"mappings":";;;AAGA,gEAA4D;AAC5D,kEAA8D;AAC9D,gDAAgD;AAEhD,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;AAExC,MAAa,iBAAiB;IAC5B,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,SAAqB,EAAE,MAAkB,EAAE,IAAa;QACzF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;YAC1D,MAAM,IAAI,kBAAS,CAAC,sBAAsB,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,oCAAoC;YACpC,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,YAAY,CAAC,mBAAmB,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS;QAC/D,MAAM,SAAS,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,GAAG,OAAO,iCAAiC,KAAK,EAAE,CAAC;QAChE,IAAI,MAAM,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC;YAChC,MAAM,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7D,CAAC;aAAM,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,8BAAa,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACtD,MAAM,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,SAAqB;QAC/C,IAAI,CAAC,SAAS,CAAC,oBAAoB,EAAE,CAAC;YACpC,MAAM,IAAI,kBAAS,CAAC,mDAAmD,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAC;QACnG,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;QACzD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,kBAAS,CAAC,0BAA0B,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;YAC1D,MAAM,IAAI,kBAAS,CAAC,0BAA0B,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;YACxE,MAAM,IAAI,kBAAS,CAAC,8BAA8B,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,SAAS,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAxCD,8CAwCC"}
@@ -0,0 +1,29 @@
1
+ import { BaseOAuthStrategy } from '../../abstract/base-oauth-strategy.abstract';
2
+ import { BaseUser } from '../../models/user.model';
3
+ import { AuthConfig } from '../../models/auth-config.model';
4
+ export declare abstract class GithubStrategy<TUser extends BaseUser = BaseUser> extends BaseOAuthStrategy<TUser> {
5
+ name: string;
6
+ private readonly clientId;
7
+ private readonly clientSecret;
8
+ private readonly callbackUrl;
9
+ constructor(config: AuthConfig);
10
+ getAuthorizationUrl(state?: string): string;
11
+ protected exchangeCodeForTokens(code: string): Promise<{
12
+ accessToken: string;
13
+ idToken?: string;
14
+ }>;
15
+ protected getUserProfile(accessToken: string): Promise<{
16
+ id: string;
17
+ email: string;
18
+ name?: string;
19
+ picture?: string;
20
+ }>;
21
+ handleCallback(code: string, state?: string): Promise<TUser>;
22
+ abstract findOrCreateUser(profile: {
23
+ id: string;
24
+ email: string;
25
+ name?: string;
26
+ picture?: string;
27
+ }, state?: string): Promise<TUser>;
28
+ }
29
+ //# sourceMappingURL=github.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/oauth/github.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAG5D,8BAAsB,cAAc,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,CAAE,SAAQ,iBAAiB,CAAC,KAAK,CAAC;IACtG,IAAI,SAAY;IAEhB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,MAAM,EAAE,UAAU;IAU9B,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;cAU3B,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;cAgBvF,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBtH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAMlE,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;CACnI"}
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GithubStrategy = void 0;
4
+ const base_oauth_strategy_abstract_1 = require("../../abstract/base-oauth-strategy.abstract");
5
+ const errors_1 = require("../../models/errors");
6
+ class GithubStrategy extends base_oauth_strategy_abstract_1.BaseOAuthStrategy {
7
+ constructor(config) {
8
+ super();
9
+ this.name = 'github';
10
+ if (!config.oauth?.github) {
11
+ throw new errors_1.AuthError('GitHub OAuth not configured', 'OAUTH_NOT_CONFIGURED', 500);
12
+ }
13
+ this.clientId = config.oauth.github.clientId;
14
+ this.clientSecret = config.oauth.github.clientSecret;
15
+ this.callbackUrl = config.oauth.github.callbackUrl;
16
+ }
17
+ getAuthorizationUrl(state) {
18
+ const params = new URLSearchParams({
19
+ client_id: this.clientId,
20
+ redirect_uri: this.callbackUrl,
21
+ scope: 'user:email',
22
+ ...(state ? { state } : {}),
23
+ });
24
+ return `https://github.com/login/oauth/authorize?${params.toString()}`;
25
+ }
26
+ async exchangeCodeForTokens(code) {
27
+ const res = await fetch('https://github.com/login/oauth/access_token', {
28
+ method: 'POST',
29
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
30
+ body: JSON.stringify({
31
+ client_id: this.clientId,
32
+ client_secret: this.clientSecret,
33
+ code,
34
+ redirect_uri: this.callbackUrl,
35
+ }),
36
+ });
37
+ if (!res.ok)
38
+ throw new errors_1.AuthError('GitHub token exchange failed', 'OAUTH_TOKEN_EXCHANGE_FAILED', 401);
39
+ const data = await res.json();
40
+ return { accessToken: data.access_token };
41
+ }
42
+ async getUserProfile(accessToken) {
43
+ const [userRes, emailRes] = await Promise.all([
44
+ fetch('https://api.github.com/user', {
45
+ headers: { Authorization: `token ${accessToken}`, Accept: 'application/vnd.github.v3+json' },
46
+ }),
47
+ fetch('https://api.github.com/user/emails', {
48
+ headers: { Authorization: `token ${accessToken}`, Accept: 'application/vnd.github.v3+json' },
49
+ }),
50
+ ]);
51
+ if (!userRes.ok)
52
+ throw new errors_1.AuthError('Failed to get GitHub user profile', 'OAUTH_PROFILE_FAILED', 401);
53
+ const user = await userRes.json();
54
+ let email = user.email ?? '';
55
+ if (!email && emailRes.ok) {
56
+ const emails = await emailRes.json();
57
+ const primary = emails.find(e => e.primary && e.verified);
58
+ email = primary?.email ?? emails[0]?.email ?? '';
59
+ }
60
+ return { id: String(user.id), email, name: user.name ?? user.login, picture: user.avatar_url };
61
+ }
62
+ async handleCallback(code, state) {
63
+ const { accessToken } = await this.exchangeCodeForTokens(code);
64
+ const profile = await this.getUserProfile(accessToken);
65
+ return this.findOrCreateUser(profile, state);
66
+ }
67
+ }
68
+ exports.GithubStrategy = GithubStrategy;
69
+ //# sourceMappingURL=github.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.strategy.js","sourceRoot":"","sources":["../../../src/strategies/oauth/github.strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { BaseOAuthStrategy } from '../../abstract/base-oauth-strategy.abstract';
2
+ import { BaseUser } from '../../models/user.model';
3
+ import { AuthConfig } from '../../models/auth-config.model';
4
+ export declare abstract class GoogleStrategy<TUser extends BaseUser = BaseUser> extends BaseOAuthStrategy<TUser> {
5
+ name: string;
6
+ private readonly clientId;
7
+ private readonly clientSecret;
8
+ private readonly callbackUrl;
9
+ constructor(config: AuthConfig);
10
+ getAuthorizationUrl(state?: string): string;
11
+ protected exchangeCodeForTokens(code: string): Promise<{
12
+ accessToken: string;
13
+ idToken?: string;
14
+ }>;
15
+ protected getUserProfile(accessToken: string): Promise<{
16
+ id: string;
17
+ email: string;
18
+ name?: string;
19
+ picture?: string;
20
+ }>;
21
+ handleCallback(code: string, state?: string): Promise<TUser>;
22
+ abstract findOrCreateUser(profile: {
23
+ id: string;
24
+ email: string;
25
+ name?: string;
26
+ picture?: string;
27
+ }, state?: string): Promise<TUser>;
28
+ }
29
+ //# sourceMappingURL=google.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/oauth/google.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAG5D,8BAAsB,cAAc,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,CAAE,SAAQ,iBAAiB,CAAC,KAAK,CAAC;IACtG,IAAI,SAAY;IAEhB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,MAAM,EAAE,UAAU;IAU9B,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;cAY3B,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;cAiBvF,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAStH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAMlE,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;CACnI"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GoogleStrategy = void 0;
4
+ const base_oauth_strategy_abstract_1 = require("../../abstract/base-oauth-strategy.abstract");
5
+ const errors_1 = require("../../models/errors");
6
+ class GoogleStrategy extends base_oauth_strategy_abstract_1.BaseOAuthStrategy {
7
+ constructor(config) {
8
+ super();
9
+ this.name = 'google';
10
+ if (!config.oauth?.google) {
11
+ throw new errors_1.AuthError('Google OAuth not configured', 'OAUTH_NOT_CONFIGURED', 500);
12
+ }
13
+ this.clientId = config.oauth.google.clientId;
14
+ this.clientSecret = config.oauth.google.clientSecret;
15
+ this.callbackUrl = config.oauth.google.callbackUrl;
16
+ }
17
+ getAuthorizationUrl(state) {
18
+ const params = new URLSearchParams({
19
+ client_id: this.clientId,
20
+ redirect_uri: this.callbackUrl,
21
+ response_type: 'code',
22
+ scope: 'openid email profile',
23
+ access_type: 'offline',
24
+ ...(state ? { state } : {}),
25
+ });
26
+ return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
27
+ }
28
+ async exchangeCodeForTokens(code) {
29
+ const res = await fetch('https://oauth2.googleapis.com/token', {
30
+ method: 'POST',
31
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
32
+ body: new URLSearchParams({
33
+ code,
34
+ client_id: this.clientId,
35
+ client_secret: this.clientSecret,
36
+ redirect_uri: this.callbackUrl,
37
+ grant_type: 'authorization_code',
38
+ }).toString(),
39
+ });
40
+ if (!res.ok)
41
+ throw new errors_1.AuthError('Google token exchange failed', 'OAUTH_TOKEN_EXCHANGE_FAILED', 401);
42
+ const data = await res.json();
43
+ return { accessToken: data.access_token, idToken: data.id_token };
44
+ }
45
+ async getUserProfile(accessToken) {
46
+ const res = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', {
47
+ headers: { Authorization: `Bearer ${accessToken}` },
48
+ });
49
+ if (!res.ok)
50
+ throw new errors_1.AuthError('Failed to get Google user profile', 'OAUTH_PROFILE_FAILED', 401);
51
+ const data = await res.json();
52
+ return { id: data.sub, email: data.email, name: data.name, picture: data.picture };
53
+ }
54
+ async handleCallback(code, state) {
55
+ const { accessToken } = await this.exchangeCodeForTokens(code);
56
+ const profile = await this.getUserProfile(accessToken);
57
+ return this.findOrCreateUser(profile, state);
58
+ }
59
+ }
60
+ exports.GoogleStrategy = GoogleStrategy;
61
+ //# sourceMappingURL=google.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.strategy.js","sourceRoot":"","sources":["../../../src/strategies/oauth/google.strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { IUserStore } from '../../interfaces/user-store.interface';
2
+ import { AuthConfig } from '../../models/auth-config.model';
3
+ export declare class SmsStrategy {
4
+ sendCode(phone: string, userId: string, userStore: IUserStore, config: AuthConfig): Promise<void>;
5
+ verify(userId: string, code: string, userStore: IUserStore): Promise<boolean>;
6
+ }
7
+ //# sourceMappingURL=sms.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sms.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/sms/sms.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAO5D,qBAAa,WAAW;IAChB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAajG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;CAcpF"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SmsStrategy = void 0;
4
+ const sms_service_1 = require("../../services/sms.service");
5
+ const password_service_1 = require("../../services/password.service");
6
+ const errors_1 = require("../../models/errors");
7
+ const passwordService = new password_service_1.PasswordService();
8
+ class SmsStrategy {
9
+ async sendCode(phone, userId, userStore, config) {
10
+ if (!config.sms) {
11
+ throw new errors_1.AuthError('SMS not configured', 'SMS_NOT_CONFIGURED', 500);
12
+ }
13
+ const smsService = new sms_service_1.SmsService(config.sms);
14
+ const code = smsService.generateCode();
15
+ const hashedCode = await passwordService.hash(code, 10);
16
+ const expiresInMin = config.sms.codeExpiresInMinutes ?? 10;
17
+ const expiry = new Date(Date.now() + expiresInMin * 60 * 1000);
18
+ await userStore.updateSmsCode(userId, hashedCode, expiry);
19
+ await smsService.sendSms(phone, `Your verification code is: ${code}`);
20
+ }
21
+ async verify(userId, code, userStore) {
22
+ const user = await userStore.findById(userId);
23
+ if (!user)
24
+ return false;
25
+ if (!user.smsCode)
26
+ return false;
27
+ if (user.smsCodeExpiry && new Date() > user.smsCodeExpiry) {
28
+ await userStore.updateSmsCode(userId, null, null);
29
+ return false;
30
+ }
31
+ const valid = await passwordService.compare(code, user.smsCode);
32
+ if (valid) {
33
+ await userStore.updateSmsCode(userId, null, null);
34
+ }
35
+ return valid;
36
+ }
37
+ }
38
+ exports.SmsStrategy = SmsStrategy;
39
+ //# sourceMappingURL=sms.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sms.strategy.js","sourceRoot":"","sources":["../../../src/strategies/sms/sms.strategy.ts"],"names":[],"mappings":";;;AAEA,4DAAwD;AACxD,sEAAkE;AAClE,gDAAgD;AAEhD,MAAM,eAAe,GAAG,IAAI,kCAAe,EAAE,CAAC;AAE9C,MAAa,WAAW;IACtB,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,MAAc,EAAE,SAAqB,EAAE,MAAkB;QACrF,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;YAChB,MAAM,IAAI,kBAAS,CAAC,oBAAoB,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,wBAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,YAAY,EAAE,CAAC;QACvC,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxD,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC/D,MAAM,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAC1D,MAAM,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,8BAA8B,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,IAAY,EAAE,SAAqB;QAC9D,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YAC1D,MAAM,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAClD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAChE,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AA5BD,kCA4BC"}
@@ -0,0 +1,12 @@
1
+ import { IUserStore } from '../../interfaces/user-store.interface';
2
+ export declare class TotpStrategy {
3
+ generateSecret(email: string, appName?: string): {
4
+ secret: string;
5
+ otpauthUrl: string;
6
+ qrCode: Promise<string>;
7
+ };
8
+ verify(token: string, secret: string): Promise<boolean>;
9
+ enable(userId: string, secret: string, userStore: IUserStore): Promise<void>;
10
+ disable(userId: string, userStore: IUserStore): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=totp.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"totp.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/two-factor/totp.strategy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AAOnE,qBAAa,YAAY;IACvB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,MAAoB,GAAG;QAC5D,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;KACzB;IAOK,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKvD,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5E,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAGpE"}
@@ -0,0 +1,32 @@
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.TotpStrategy = void 0;
7
+ const otplib_1 = require("otplib");
8
+ const qrcode_1 = __importDefault(require("qrcode"));
9
+ const totp = new otplib_1.TOTP({
10
+ crypto: new otplib_1.NobleCryptoPlugin(),
11
+ base32: new otplib_1.ScureBase32Plugin(),
12
+ });
13
+ class TotpStrategy {
14
+ generateSecret(email, appName = 'node-auth') {
15
+ const secret = totp.generateSecret();
16
+ const otpauthUrl = totp.toURI({ label: email, issuer: appName, secret });
17
+ const qrCode = qrcode_1.default.toDataURL(otpauthUrl);
18
+ return { secret, otpauthUrl, qrCode };
19
+ }
20
+ async verify(token, secret) {
21
+ const result = await totp.verify(token, { secret });
22
+ return result.valid;
23
+ }
24
+ async enable(userId, secret, userStore) {
25
+ await userStore.updateTotpSecret(userId, secret);
26
+ }
27
+ async disable(userId, userStore) {
28
+ await userStore.updateTotpSecret(userId, null);
29
+ }
30
+ }
31
+ exports.TotpStrategy = TotpStrategy;
32
+ //# sourceMappingURL=totp.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"totp.strategy.js","sourceRoot":"","sources":["../../../src/strategies/two-factor/totp.strategy.ts"],"names":[],"mappings":";;;;;;AAAA,mCAAoE;AACpE,oDAA4B;AAG5B,MAAM,IAAI,GAAG,IAAI,aAAI,CAAC;IACpB,MAAM,EAAE,IAAI,0BAAiB,EAAE;IAC/B,MAAM,EAAE,IAAI,0BAAiB,EAAE;CAChC,CAAC,CAAC;AAEH,MAAa,YAAY;IACvB,cAAc,CAAC,KAAa,EAAE,UAAkB,WAAW;QAKzD,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACzE,MAAM,MAAM,GAAG,gBAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAC5C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,MAAc;QACxC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QACpD,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,MAAc,EAAE,SAAqB;QAChE,MAAM,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,SAAqB;QACjD,MAAM,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;CACF;AAxBD,oCAwBC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@nik2208/node-auth",
3
+ "version": "1.0.2",
4
+ "description": "Database-agnostic JWT authentication library for Node.js",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "test": "vitest run",
9
+ "test:coverage": "vitest run --coverage"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/nik2208/node-auth.git"
14
+ },
15
+ "keywords": [],
16
+ "author": "",
17
+ "license": "ISC",
18
+ "type": "commonjs",
19
+ "bugs": {
20
+ "url": "https://github.com/nik2208/node-auth/issues"
21
+ },
22
+ "homepage": "https://github.com/nik2208/node-auth#readme",
23
+ "dependencies": {
24
+ "bcryptjs": "^3.0.3",
25
+ "jsonwebtoken": "^9.0.3",
26
+ "otplib": "^13.3.0",
27
+ "qrcode": "^1.5.4"
28
+ },
29
+ "devDependencies": {
30
+ "@types/bcryptjs": "^2.4.6",
31
+ "@types/express": "^5.0.6",
32
+ "@types/jsonwebtoken": "^9.0.10",
33
+ "@types/node": "^25.3.0",
34
+ "@types/qrcode": "^1.5.6",
35
+ "@types/supertest": "^6.0.3",
36
+ "@vitest/coverage-v8": "^4.0.18",
37
+ "express": "^5.2.1",
38
+ "supertest": "^7.2.2",
39
+ "typescript": "^5.9.3",
40
+ "vitest": "^4.0.18"
41
+ },
42
+ "types": "dist/index.d.ts",
43
+ "files": [
44
+ "dist",
45
+ "README.md",
46
+ "LICENSE"
47
+ ]
48
+ }