@awesome-lang-auth/node 1.10.1
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/LICENSE +21 -0
- package/README.detailed.md +4059 -0
- package/README.md +248 -0
- package/dist/abstract/base-auth-strategy.abstract.d.ts +7 -0
- package/dist/abstract/base-auth-strategy.abstract.d.ts.map +1 -0
- package/dist/abstract/base-auth-strategy.abstract.js +7 -0
- package/dist/abstract/base-auth-strategy.abstract.js.map +1 -0
- package/dist/abstract/base-oauth-strategy.abstract.d.ts +27 -0
- package/dist/abstract/base-oauth-strategy.abstract.d.ts.map +1 -0
- package/dist/abstract/base-oauth-strategy.abstract.js +11 -0
- package/dist/abstract/base-oauth-strategy.abstract.js.map +1 -0
- package/dist/adapters/express.d.ts +45 -0
- package/dist/adapters/express.d.ts.map +1 -0
- package/dist/adapters/express.js +49 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/fastify.d.ts +72 -0
- package/dist/adapters/fastify.d.ts.map +1 -0
- package/dist/adapters/fastify.js +63 -0
- package/dist/adapters/fastify.js.map +1 -0
- package/dist/auth-configurator.d.ts +65 -0
- package/dist/auth-configurator.d.ts.map +1 -0
- package/dist/auth-configurator.js +127 -0
- package/dist/auth-configurator.js.map +1 -0
- package/dist/events/auth-event-bus.d.ts +68 -0
- package/dist/events/auth-event-bus.d.ts.map +1 -0
- package/dist/events/auth-event-bus.js +60 -0
- package/dist/events/auth-event-bus.js.map +1 -0
- package/dist/events/auth-event-names.d.ts +34 -0
- package/dist/events/auth-event-names.d.ts.map +1 -0
- package/dist/events/auth-event-names.js +41 -0
- package/dist/events/auth-event-names.js.map +1 -0
- package/dist/http-types.d.ts +135 -0
- package/dist/http-types.d.ts.map +1 -0
- package/dist/http-types.js +18 -0
- package/dist/http-types.js.map +1 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/api-key-store.interface.d.ts +94 -0
- package/dist/interfaces/api-key-store.interface.d.ts.map +1 -0
- package/dist/interfaces/api-key-store.interface.js +3 -0
- package/dist/interfaces/api-key-store.interface.js.map +1 -0
- package/dist/interfaces/auth-strategy.interface.d.ts +6 -0
- package/dist/interfaces/auth-strategy.interface.d.ts.map +1 -0
- package/dist/interfaces/auth-strategy.interface.js +3 -0
- package/dist/interfaces/auth-strategy.interface.js.map +1 -0
- package/dist/interfaces/linked-accounts-store.interface.d.ts +74 -0
- package/dist/interfaces/linked-accounts-store.interface.d.ts.map +1 -0
- package/dist/interfaces/linked-accounts-store.interface.js +3 -0
- package/dist/interfaces/linked-accounts-store.interface.js.map +1 -0
- package/dist/interfaces/pending-link-store.interface.d.ts +77 -0
- package/dist/interfaces/pending-link-store.interface.d.ts.map +1 -0
- package/dist/interfaces/pending-link-store.interface.js +3 -0
- package/dist/interfaces/pending-link-store.interface.js.map +1 -0
- package/dist/interfaces/roles-permissions-store.interface.d.ts +129 -0
- package/dist/interfaces/roles-permissions-store.interface.d.ts.map +1 -0
- package/dist/interfaces/roles-permissions-store.interface.js +3 -0
- package/dist/interfaces/roles-permissions-store.interface.js.map +1 -0
- package/dist/interfaces/session-store.interface.d.ts +92 -0
- package/dist/interfaces/session-store.interface.d.ts.map +1 -0
- package/dist/interfaces/session-store.interface.js +3 -0
- package/dist/interfaces/session-store.interface.js.map +1 -0
- package/dist/interfaces/settings-store.interface.d.ts +91 -0
- package/dist/interfaces/settings-store.interface.d.ts.map +1 -0
- package/dist/interfaces/settings-store.interface.js +3 -0
- package/dist/interfaces/settings-store.interface.js.map +1 -0
- package/dist/interfaces/sse-distributor.interface.d.ts +25 -0
- package/dist/interfaces/sse-distributor.interface.d.ts.map +1 -0
- package/dist/interfaces/sse-distributor.interface.js +3 -0
- package/dist/interfaces/sse-distributor.interface.js.map +1 -0
- package/dist/interfaces/telemetry-store.interface.d.ts +72 -0
- package/dist/interfaces/telemetry-store.interface.d.ts.map +1 -0
- package/dist/interfaces/telemetry-store.interface.js +3 -0
- package/dist/interfaces/telemetry-store.interface.js.map +1 -0
- package/dist/interfaces/template-store.interface.d.ts +37 -0
- package/dist/interfaces/template-store.interface.d.ts.map +1 -0
- package/dist/interfaces/template-store.interface.js +3 -0
- package/dist/interfaces/template-store.interface.js.map +1 -0
- package/dist/interfaces/tenant-store.interface.d.ts +97 -0
- package/dist/interfaces/tenant-store.interface.d.ts.map +1 -0
- package/dist/interfaces/tenant-store.interface.js +3 -0
- package/dist/interfaces/tenant-store.interface.js.map +1 -0
- package/dist/interfaces/token-store.interface.d.ts +10 -0
- package/dist/interfaces/token-store.interface.d.ts.map +1 -0
- package/dist/interfaces/token-store.interface.js +3 -0
- package/dist/interfaces/token-store.interface.js.map +1 -0
- package/dist/interfaces/user-metadata-store.interface.d.ts +50 -0
- package/dist/interfaces/user-metadata-store.interface.d.ts.map +1 -0
- package/dist/interfaces/user-metadata-store.interface.js +3 -0
- package/dist/interfaces/user-metadata-store.interface.js.map +1 -0
- package/dist/interfaces/user-store.interface.d.ts +113 -0
- package/dist/interfaces/user-store.interface.d.ts.map +1 -0
- package/dist/interfaces/user-store.interface.js +3 -0
- package/dist/interfaces/user-store.interface.js.map +1 -0
- package/dist/interfaces/webhook-store.interface.d.ts +139 -0
- package/dist/interfaces/webhook-store.interface.d.ts.map +1 -0
- package/dist/interfaces/webhook-store.interface.js +3 -0
- package/dist/interfaces/webhook-store.interface.js.map +1 -0
- package/dist/middleware/api-key.middleware.d.ts +35 -0
- package/dist/middleware/api-key.middleware.d.ts.map +1 -0
- package/dist/middleware/api-key.middleware.js +45 -0
- package/dist/middleware/api-key.middleware.js.map +1 -0
- package/dist/middleware/auth.middleware.d.ts +13 -0
- package/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/dist/middleware/auth.middleware.js +55 -0
- package/dist/middleware/auth.middleware.js.map +1 -0
- package/dist/middleware/jwks-auth.middleware.d.ts +18 -0
- package/dist/middleware/jwks-auth.middleware.d.ts.map +1 -0
- package/dist/middleware/jwks-auth.middleware.js +77 -0
- package/dist/middleware/jwks-auth.middleware.js.map +1 -0
- package/dist/models/api-key.model.d.ts +66 -0
- package/dist/models/api-key.model.d.ts.map +1 -0
- package/dist/models/api-key.model.js +3 -0
- package/dist/models/api-key.model.js.map +1 -0
- package/dist/models/auth-config.model.d.ts +387 -0
- package/dist/models/auth-config.model.d.ts.map +1 -0
- package/dist/models/auth-config.model.js +3 -0
- package/dist/models/auth-config.model.js.map +1 -0
- package/dist/models/errors.d.ts +7 -0
- package/dist/models/errors.d.ts.map +1 -0
- package/dist/models/errors.js +14 -0
- package/dist/models/errors.js.map +1 -0
- package/dist/models/session.model.d.ts +28 -0
- package/dist/models/session.model.d.ts.map +1 -0
- package/dist/models/session.model.js +3 -0
- package/dist/models/session.model.js.map +1 -0
- package/dist/models/tenant.model.d.ts +20 -0
- package/dist/models/tenant.model.d.ts.map +1 -0
- package/dist/models/tenant.model.js +3 -0
- package/dist/models/tenant.model.js.map +1 -0
- package/dist/models/token.model.d.ts +21 -0
- package/dist/models/token.model.d.ts.map +1 -0
- package/dist/models/token.model.js +3 -0
- package/dist/models/token.model.js.map +1 -0
- package/dist/models/user.model.d.ts +92 -0
- package/dist/models/user.model.d.ts.map +1 -0
- package/dist/models/user.model.js +3 -0
- package/dist/models/user.model.js.map +1 -0
- package/dist/router/admin.router.d.ts +188 -0
- package/dist/router/admin.router.d.ts.map +1 -0
- package/dist/router/admin.router.js +1507 -0
- package/dist/router/admin.router.js.map +1 -0
- package/dist/router/auth.router.d.ts +199 -0
- package/dist/router/auth.router.d.ts.map +1 -0
- package/dist/router/auth.router.js +1636 -0
- package/dist/router/auth.router.js.map +1 -0
- package/dist/router/openapi.d.ts +98 -0
- package/dist/router/openapi.d.ts.map +1 -0
- package/dist/router/openapi.js +1518 -0
- package/dist/router/openapi.js.map +1 -0
- package/dist/router/router-events.d.ts +38 -0
- package/dist/router/router-events.d.ts.map +1 -0
- package/dist/router/router-events.js +74 -0
- package/dist/router/router-events.js.map +1 -0
- package/dist/router/tools.router.d.ts +104 -0
- package/dist/router/tools.router.d.ts.map +1 -0
- package/dist/router/tools.router.js +227 -0
- package/dist/router/tools.router.js.map +1 -0
- package/dist/router/ui.router.d.ts +49 -0
- package/dist/router/ui.router.d.ts.map +1 -0
- package/dist/router/ui.router.js +272 -0
- package/dist/router/ui.router.js.map +1 -0
- package/dist/services/api-key.service.d.ts +53 -0
- package/dist/services/api-key.service.d.ts.map +1 -0
- package/dist/services/api-key.service.js +66 -0
- package/dist/services/api-key.service.js.map +1 -0
- package/dist/services/jwks.service.d.ts +73 -0
- package/dist/services/jwks.service.d.ts.map +1 -0
- package/dist/services/jwks.service.js +174 -0
- package/dist/services/jwks.service.js.map +1 -0
- package/dist/services/mailer.service.d.ts +30 -0
- package/dist/services/mailer.service.d.ts.map +1 -0
- package/dist/services/mailer.service.js +248 -0
- package/dist/services/mailer.service.js.map +1 -0
- package/dist/services/notification.service.d.ts +110 -0
- package/dist/services/notification.service.d.ts.map +1 -0
- package/dist/services/notification.service.js +79 -0
- package/dist/services/notification.service.js.map +1 -0
- package/dist/services/password.service.d.ts +5 -0
- package/dist/services/password.service.d.ts.map +1 -0
- package/dist/services/password.service.js +17 -0
- package/dist/services/password.service.js.map +1 -0
- package/dist/services/sms.service.d.ts +14 -0
- package/dist/services/sms.service.d.ts.map +1 -0
- package/dist/services/sms.service.js +51 -0
- package/dist/services/sms.service.js.map +1 -0
- package/dist/services/token.service.d.ts +62 -0
- package/dist/services/token.service.d.ts.map +1 -0
- package/dist/services/token.service.js +354 -0
- package/dist/services/token.service.js.map +1 -0
- package/dist/stores/memory-template.store.d.ts +12 -0
- package/dist/stores/memory-template.store.d.ts.map +1 -0
- package/dist/stores/memory-template.store.js +35 -0
- package/dist/stores/memory-template.store.js.map +1 -0
- package/dist/strategies/api-key/api-key.strategy.d.ts +72 -0
- package/dist/strategies/api-key/api-key.strategy.d.ts.map +1 -0
- package/dist/strategies/api-key/api-key.strategy.js +182 -0
- package/dist/strategies/api-key/api-key.strategy.js.map +1 -0
- package/dist/strategies/local/local.strategy.d.ts +19 -0
- package/dist/strategies/local/local.strategy.d.ts.map +1 -0
- package/dist/strategies/local/local.strategy.js +45 -0
- package/dist/strategies/local/local.strategy.js.map +1 -0
- package/dist/strategies/magic-link/magic-link.strategy.d.ts +8 -0
- package/dist/strategies/magic-link/magic-link.strategy.d.ts.map +1 -0
- package/dist/strategies/magic-link/magic-link.strategy.js +53 -0
- package/dist/strategies/magic-link/magic-link.strategy.js.map +1 -0
- package/dist/strategies/oauth/generic-oauth.strategy.d.ts +120 -0
- package/dist/strategies/oauth/generic-oauth.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth/generic-oauth.strategy.js +88 -0
- package/dist/strategies/oauth/generic-oauth.strategy.js.map +1 -0
- package/dist/strategies/oauth/github.strategy.d.ts +31 -0
- package/dist/strategies/oauth/github.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth/github.strategy.js +72 -0
- package/dist/strategies/oauth/github.strategy.js.map +1 -0
- package/dist/strategies/oauth/google.strategy.d.ts +31 -0
- package/dist/strategies/oauth/google.strategy.d.ts.map +1 -0
- package/dist/strategies/oauth/google.strategy.js +61 -0
- package/dist/strategies/oauth/google.strategy.js.map +1 -0
- package/dist/strategies/sms/sms.strategy.d.ts +7 -0
- package/dist/strategies/sms/sms.strategy.d.ts.map +1 -0
- package/dist/strategies/sms/sms.strategy.js +39 -0
- package/dist/strategies/sms/sms.strategy.js.map +1 -0
- package/dist/strategies/two-factor/totp.strategy.d.ts +12 -0
- package/dist/strategies/two-factor/totp.strategy.d.ts.map +1 -0
- package/dist/strategies/two-factor/totp.strategy.js +32 -0
- package/dist/strategies/two-factor/totp.strategy.js.map +1 -0
- package/dist/tools/auth-tools.d.ts +200 -0
- package/dist/tools/auth-tools.d.ts.map +1 -0
- package/dist/tools/auth-tools.js +232 -0
- package/dist/tools/auth-tools.js.map +1 -0
- package/dist/tools/sse-manager.d.ts +118 -0
- package/dist/tools/sse-manager.d.ts.map +1 -0
- package/dist/tools/sse-manager.js +163 -0
- package/dist/tools/sse-manager.js.map +1 -0
- package/dist/tools/sse-notify.decorator.d.ts +74 -0
- package/dist/tools/sse-notify.decorator.d.ts.map +1 -0
- package/dist/tools/sse-notify.decorator.js +78 -0
- package/dist/tools/sse-notify.decorator.js.map +1 -0
- package/dist/tools/webhook-action.d.ts +130 -0
- package/dist/tools/webhook-action.d.ts.map +1 -0
- package/dist/tools/webhook-action.js +144 -0
- package/dist/tools/webhook-action.js.map +1 -0
- package/dist/tools/webhook-sender.d.ts +31 -0
- package/dist/tools/webhook-sender.d.ts.map +1 -0
- package/dist/tools/webhook-sender.js +80 -0
- package/dist/tools/webhook-sender.js.map +1 -0
- package/dist/ui-assets/2fa.html +115 -0
- package/dist/ui-assets/account-conflict.html +108 -0
- package/dist/ui-assets/admin.css +263 -0
- package/dist/ui-assets/admin.js +1927 -0
- package/dist/ui-assets/auth.js +725 -0
- package/dist/ui-assets/base.css +219 -0
- package/dist/ui-assets/forgot-password.html +93 -0
- package/dist/ui-assets/link-verify.html +74 -0
- package/dist/ui-assets/login.html +135 -0
- package/dist/ui-assets/magic-link.html +112 -0
- package/dist/ui-assets/register.html +122 -0
- package/dist/ui-assets/reset-password.html +103 -0
- package/dist/ui-assets/ui-i18n-keys.json +78 -0
- package/dist/ui-assets/verify-email.html +66 -0
- package/package.json +89 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GenericOAuthStrategy = void 0;
|
|
4
|
+
const base_oauth_strategy_abstract_1 = require("../../abstract/base-oauth-strategy.abstract");
|
|
5
|
+
const errors_1 = require("../../models/errors");
|
|
6
|
+
/**
|
|
7
|
+
* Generic OAuth 2.0 strategy.
|
|
8
|
+
*
|
|
9
|
+
* Extend this class to add OAuth login support for any provider that
|
|
10
|
+
* follows the standard Authorization Code flow with a JSON user-info
|
|
11
|
+
* endpoint. Only `findOrCreateUser` needs to be implemented.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* class MicrosoftStrategy extends GenericOAuthStrategy<MyUser> {
|
|
16
|
+
* async findOrCreateUser(profile) {
|
|
17
|
+
* let user = await userStore.findByProviderAccount('microsoft', profile.id);
|
|
18
|
+
* if (!user) user = await userStore.create({ email: profile.email, loginProvider: 'microsoft' });
|
|
19
|
+
* return user as MyUser;
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
class GenericOAuthStrategy extends base_oauth_strategy_abstract_1.BaseOAuthStrategy {
|
|
25
|
+
constructor(config) {
|
|
26
|
+
super();
|
|
27
|
+
this.name = config.name;
|
|
28
|
+
this.config = config;
|
|
29
|
+
}
|
|
30
|
+
getAuthorizationUrl(state) {
|
|
31
|
+
const scope = Array.isArray(this.config.scope)
|
|
32
|
+
? this.config.scope.join(' ')
|
|
33
|
+
: this.config.scope;
|
|
34
|
+
const params = new URLSearchParams({
|
|
35
|
+
client_id: this.config.clientId,
|
|
36
|
+
redirect_uri: this.config.callbackUrl,
|
|
37
|
+
response_type: 'code',
|
|
38
|
+
scope,
|
|
39
|
+
...this.config.additionalAuthParams,
|
|
40
|
+
...(state ? { state } : {}),
|
|
41
|
+
});
|
|
42
|
+
return `${this.config.authorizationUrl}?${params.toString()}`;
|
|
43
|
+
}
|
|
44
|
+
async exchangeCodeForTokens(code) {
|
|
45
|
+
const res = await fetch(this.config.tokenUrl, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },
|
|
48
|
+
body: new URLSearchParams({
|
|
49
|
+
code,
|
|
50
|
+
client_id: this.config.clientId,
|
|
51
|
+
client_secret: this.config.clientSecret,
|
|
52
|
+
redirect_uri: this.config.callbackUrl,
|
|
53
|
+
grant_type: 'authorization_code',
|
|
54
|
+
}).toString(),
|
|
55
|
+
});
|
|
56
|
+
if (!res.ok) {
|
|
57
|
+
throw new errors_1.AuthError(`${this.name} token exchange failed`, 'OAUTH_TOKEN_EXCHANGE_FAILED', 401);
|
|
58
|
+
}
|
|
59
|
+
const data = await res.json();
|
|
60
|
+
return { accessToken: data.access_token, idToken: data.id_token };
|
|
61
|
+
}
|
|
62
|
+
async getUserProfile(accessToken) {
|
|
63
|
+
const res = await fetch(this.config.userInfoUrl, {
|
|
64
|
+
headers: { Authorization: `Bearer ${accessToken}`, Accept: 'application/json' },
|
|
65
|
+
});
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
throw new errors_1.AuthError(`Failed to get ${this.name} user profile`, 'OAUTH_PROFILE_FAILED', 401);
|
|
68
|
+
}
|
|
69
|
+
const raw = await res.json();
|
|
70
|
+
if (this.config.mapProfile) {
|
|
71
|
+
return this.config.mapProfile(raw);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
id: String(raw['id'] ?? raw['sub'] ?? ''),
|
|
75
|
+
email: String(raw['email'] ?? ''),
|
|
76
|
+
emailVerified: raw['email_verified'],
|
|
77
|
+
name: raw['name'],
|
|
78
|
+
picture: raw['picture'],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async handleCallback(code, state) {
|
|
82
|
+
const { accessToken } = await this.exchangeCodeForTokens(code);
|
|
83
|
+
const profile = await this.getUserProfile(accessToken);
|
|
84
|
+
return this.findOrCreateUser(profile, state);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.GenericOAuthStrategy = GenericOAuthStrategy;
|
|
88
|
+
//# sourceMappingURL=generic-oauth.strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-oauth.strategy.js","sourceRoot":"","sources":["../../../src/strategies/oauth/generic-oauth.strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
emailVerified?: boolean;
|
|
19
|
+
name?: string;
|
|
20
|
+
picture?: string;
|
|
21
|
+
}>;
|
|
22
|
+
handleCallback(code: string, state?: string): Promise<TUser>;
|
|
23
|
+
abstract findOrCreateUser(profile: {
|
|
24
|
+
id: string;
|
|
25
|
+
email: string;
|
|
26
|
+
emailVerified?: boolean;
|
|
27
|
+
name?: string;
|
|
28
|
+
picture?: string;
|
|
29
|
+
}, state?: string): Promise<TUser>;
|
|
30
|
+
}
|
|
31
|
+
//# 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,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAuB/I,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,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;CAC5J"}
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
let emailVerified;
|
|
56
|
+
if (!email && emailRes.ok) {
|
|
57
|
+
const emails = await emailRes.json();
|
|
58
|
+
const primary = emails.find(e => e.primary && e.verified);
|
|
59
|
+
const primaryEntry = primary ?? emails[0];
|
|
60
|
+
email = primaryEntry?.email ?? '';
|
|
61
|
+
emailVerified = primaryEntry?.verified;
|
|
62
|
+
}
|
|
63
|
+
return { id: String(user.id), email, emailVerified, name: user.name ?? user.login, picture: user.avatar_url };
|
|
64
|
+
}
|
|
65
|
+
async handleCallback(code, state) {
|
|
66
|
+
const { accessToken } = await this.exchangeCodeForTokens(code);
|
|
67
|
+
const profile = await this.getUserProfile(accessToken);
|
|
68
|
+
return this.findOrCreateUser(profile, state);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.GithubStrategy = GithubStrategy;
|
|
72
|
+
//# 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,31 @@
|
|
|
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
|
+
emailVerified?: boolean;
|
|
19
|
+
name?: string;
|
|
20
|
+
picture?: string;
|
|
21
|
+
}>;
|
|
22
|
+
handleCallback(code: string, state?: string): Promise<TUser>;
|
|
23
|
+
abstract findOrCreateUser(profile: {
|
|
24
|
+
id: string;
|
|
25
|
+
email: string;
|
|
26
|
+
emailVerified?: boolean;
|
|
27
|
+
name?: string;
|
|
28
|
+
picture?: string;
|
|
29
|
+
}, state?: string): Promise<TUser>;
|
|
30
|
+
}
|
|
31
|
+
//# 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,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAS/I,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,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;CAC5J"}
|
|
@@ -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, emailVerified: data.email_verified, 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,MAA4B,GAAG;QACpE,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 = 'awesome-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,mBAAmB;QAKjE,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"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { AuthEventBus } from '../events/auth-event-bus';
|
|
2
|
+
import { ITelemetryStore } from '../interfaces/telemetry-store.interface';
|
|
3
|
+
import { IWebhookStore } from '../interfaces/webhook-store.interface';
|
|
4
|
+
import { ISseDistributor } from '../interfaces/sse-distributor.interface';
|
|
5
|
+
import { IUserStore } from '../interfaces/user-store.interface';
|
|
6
|
+
import { SseManager } from './sse-manager';
|
|
7
|
+
import { EmailNotificationConfig, SmsNotificationConfig } from '../services/notification.service';
|
|
8
|
+
/**
|
|
9
|
+
* Options passed to {@link AuthTools}.
|
|
10
|
+
*/
|
|
11
|
+
export interface AuthToolsOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Optional telemetry store. When provided, every tracked event is also
|
|
14
|
+
* persisted via `store.save()`.
|
|
15
|
+
*/
|
|
16
|
+
telemetryStore?: ITelemetryStore;
|
|
17
|
+
/**
|
|
18
|
+
* Optional webhook store. When provided, outgoing webhooks are dispatched
|
|
19
|
+
* whenever an event is tracked.
|
|
20
|
+
*/
|
|
21
|
+
webhookStore?: IWebhookStore;
|
|
22
|
+
/**
|
|
23
|
+
* When `true`, SSE streaming is enabled. A `SseManager` instance will be
|
|
24
|
+
* created and the `/tools/stream` endpoint will be available.
|
|
25
|
+
* @default false
|
|
26
|
+
*/
|
|
27
|
+
sse?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Options forwarded to the `SseManager` constructor.
|
|
30
|
+
*/
|
|
31
|
+
sseOptions?: {
|
|
32
|
+
/** @default 30000 */
|
|
33
|
+
heartbeatIntervalMs?: number;
|
|
34
|
+
/** Distributor for cross-instance event synchronization. */
|
|
35
|
+
distributor?: ISseDistributor;
|
|
36
|
+
/** @default true */
|
|
37
|
+
deduplicate?: boolean;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Optional custom SSE distributor for AuthTools.notify().
|
|
41
|
+
* When provided it is used instead of the internal SseManager broadcaster.
|
|
42
|
+
*/
|
|
43
|
+
sseDistributor?: ISseDistributor;
|
|
44
|
+
/**
|
|
45
|
+
* Semantic version string attached to all outgoing webhook payloads.
|
|
46
|
+
* @default '1'
|
|
47
|
+
*/
|
|
48
|
+
webhookVersion?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Optional user store. Required when using `'email'` or `'sms'` channels
|
|
51
|
+
* in {@link AuthTools.notify} so the service can look up the user's contact
|
|
52
|
+
* details by `options.userId`.
|
|
53
|
+
*
|
|
54
|
+
* @since 1.8.0
|
|
55
|
+
*/
|
|
56
|
+
userStore?: IUserStore;
|
|
57
|
+
/**
|
|
58
|
+
* Email transport configuration. When provided, the `'email'` channel in
|
|
59
|
+
* {@link AuthTools.notify} will send emails using the built-in HTTP mailer.
|
|
60
|
+
*
|
|
61
|
+
* Accepts the same shape as `AuthConfig.email.mailer`.
|
|
62
|
+
*
|
|
63
|
+
* @since 1.8.0
|
|
64
|
+
*/
|
|
65
|
+
emailConfig?: EmailNotificationConfig;
|
|
66
|
+
/**
|
|
67
|
+
* SMS transport configuration. When provided, the `'sms'` channel in
|
|
68
|
+
* {@link AuthTools.notify} will send SMS messages using the built-in SMS
|
|
69
|
+
* service.
|
|
70
|
+
*
|
|
71
|
+
* Accepts the same shape as `AuthConfig.sms`.
|
|
72
|
+
*
|
|
73
|
+
* @since 1.8.0
|
|
74
|
+
*/
|
|
75
|
+
smsConfig?: SmsNotificationConfig;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Options for {@link AuthTools.track}.
|
|
79
|
+
*/
|
|
80
|
+
export interface TrackOptions {
|
|
81
|
+
userId?: string;
|
|
82
|
+
tenantId?: string;
|
|
83
|
+
sessionId?: string;
|
|
84
|
+
correlationId?: string;
|
|
85
|
+
ip?: string;
|
|
86
|
+
userAgent?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Options for {@link AuthTools.notify}.
|
|
90
|
+
*/
|
|
91
|
+
export interface NotifyOptions {
|
|
92
|
+
type?: string;
|
|
93
|
+
tenantId?: string;
|
|
94
|
+
userId?: string;
|
|
95
|
+
metadata?: Record<string, unknown>;
|
|
96
|
+
/**
|
|
97
|
+
* Delivery channels. Defaults to `['sse']` (backward-compatible).
|
|
98
|
+
*
|
|
99
|
+
* - `'sse'` — broadcast to SSE subscribers on the given `target` topic.
|
|
100
|
+
* - `'email'` — send an email to the user identified by `userId` (requires
|
|
101
|
+
* `userStore` and `emailConfig` in {@link AuthToolsOptions}).
|
|
102
|
+
* - `'sms'` — send an SMS to the user identified by `userId` (requires
|
|
103
|
+
* `userStore` and `smsConfig` in {@link AuthToolsOptions}).
|
|
104
|
+
*
|
|
105
|
+
* When multiple channels are listed, all are attempted; a failure in one
|
|
106
|
+
* channel does **not** abort the others.
|
|
107
|
+
*
|
|
108
|
+
* @since 1.8.0
|
|
109
|
+
* @default ['sse']
|
|
110
|
+
*/
|
|
111
|
+
channels?: Array<'sse' | 'email' | 'sms'>;
|
|
112
|
+
/**
|
|
113
|
+
* Email subject override. Used when `channels` includes `'email'`.
|
|
114
|
+
* Defaults to the stringified `options.type` or `'Notification'`.
|
|
115
|
+
*
|
|
116
|
+
* @since 1.8.0
|
|
117
|
+
*/
|
|
118
|
+
emailSubject?: string;
|
|
119
|
+
/**
|
|
120
|
+
* SMS message body override. Used when `channels` includes `'sms'`.
|
|
121
|
+
* Defaults to the JSON-stringified `data` payload.
|
|
122
|
+
*
|
|
123
|
+
* @since 1.8.0
|
|
124
|
+
*/
|
|
125
|
+
smsMessage?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The main tools module.
|
|
129
|
+
*
|
|
130
|
+
* Provides a unified API for telemetry tracking, real-time SSE notifications,
|
|
131
|
+
* and outgoing webhooks. All capabilities are optional and have zero overhead
|
|
132
|
+
* when disabled.
|
|
133
|
+
*
|
|
134
|
+
* ```ts
|
|
135
|
+
* import { AuthTools, AuthEventBus } from '@awesome-lang-auth/node';
|
|
136
|
+
*
|
|
137
|
+
* const bus = new AuthEventBus();
|
|
138
|
+
* const tools = new AuthTools(bus, {
|
|
139
|
+
* telemetryStore: myStore,
|
|
140
|
+
* webhookStore: myWebhookStore,
|
|
141
|
+
* sse: true,
|
|
142
|
+
* });
|
|
143
|
+
*
|
|
144
|
+
* // Track an event programmatically
|
|
145
|
+
* await tools.track('identity.auth.login.success', { user }, { userId: user.id });
|
|
146
|
+
*
|
|
147
|
+
* // Notify a topic over SSE
|
|
148
|
+
* await tools.notify('user:123', { message: 'Welcome!' });
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export declare class AuthTools {
|
|
152
|
+
readonly eventBus: AuthEventBus;
|
|
153
|
+
readonly sseManager: SseManager | null;
|
|
154
|
+
private readonly telemetryStore?;
|
|
155
|
+
private readonly webhookStore?;
|
|
156
|
+
private readonly webhookSender;
|
|
157
|
+
private readonly webhookVersion;
|
|
158
|
+
private readonly userStore?;
|
|
159
|
+
private readonly notificationService?;
|
|
160
|
+
private readonly sseDistributor?;
|
|
161
|
+
constructor(eventBus: AuthEventBus, options?: AuthToolsOptions);
|
|
162
|
+
/**
|
|
163
|
+
* Track an event: persist it (optional), emit it on the event bus, broadcast
|
|
164
|
+
* it to SSE subscribers and fire matching outgoing webhooks.
|
|
165
|
+
*
|
|
166
|
+
* @param eventName Standardised event name (see `AuthEventNames`).
|
|
167
|
+
* @param data Arbitrary event data.
|
|
168
|
+
* @param options Metadata (userId, tenantId, …).
|
|
169
|
+
*/
|
|
170
|
+
track(eventName: string, data?: unknown, options?: TrackOptions): Promise<void>;
|
|
171
|
+
/**
|
|
172
|
+
* Send a notification to one or more delivery channels.
|
|
173
|
+
*
|
|
174
|
+
* By default (or when `channels` is `['sse']`) the behaviour is identical to
|
|
175
|
+
* the original synchronous broadcast. Pass additional channels to also
|
|
176
|
+
* deliver the notification via email and/or SMS.
|
|
177
|
+
*
|
|
178
|
+
* When `'email'` or `'sms'` is included the method becomes asynchronous and
|
|
179
|
+
* requires:
|
|
180
|
+
* - `userStore` — to look up the user's contact details by `options.userId`.
|
|
181
|
+
* - `emailConfig` / `smsConfig` — transport configuration in
|
|
182
|
+
* {@link AuthToolsOptions}.
|
|
183
|
+
*
|
|
184
|
+
* Channel failures are best-effort and do not reject the returned Promise.
|
|
185
|
+
*
|
|
186
|
+
* @param target Target SSE topic (e.g. `'user:123'`, `'tenant:acme'`).
|
|
187
|
+
* @param data Payload to deliver.
|
|
188
|
+
* @param options Channels, type, tenantId, userId, metadata, etc.
|
|
189
|
+
*
|
|
190
|
+
* @since 1.8.0 (async + multi-channel)
|
|
191
|
+
*/
|
|
192
|
+
notify<T = unknown>(target: string, data: T, options?: NotifyOptions): Promise<void>;
|
|
193
|
+
/**
|
|
194
|
+
* Resolve the SSE topics an event should be broadcast to.
|
|
195
|
+
* Always includes `'global'`; additionally adds tenant and user topics when
|
|
196
|
+
* the corresponding IDs are present.
|
|
197
|
+
*/
|
|
198
|
+
private resolveTopics;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=auth-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-tools.d.ts","sourceRoot":"","sources":["../../src/tools/auth-tools.ts"],"names":[],"mappings":"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"}
|