@hed-hog/core 0.0.355 → 0.0.358
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/ai/ai.service.d.ts +3 -12
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +34 -125
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/auth/guards/auth.guard.d.ts +6 -1
- package/dist/auth/guards/auth.guard.d.ts.map +1 -1
- package/dist/auth/guards/auth.guard.js +33 -2
- package/dist/auth/guards/auth.guard.js.map +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +3 -3
- package/dist/core.module.js.map +1 -1
- package/dist/file/file.controller.d.ts +4 -2
- package/dist/file/file.controller.d.ts.map +1 -1
- package/dist/file/file.controller.js +44 -38
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +2 -2
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +58 -89
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/provider/azure.provider.d.ts.map +1 -1
- package/dist/file/provider/azure.provider.js +10 -15
- package/dist/file/provider/azure.provider.js.map +1 -1
- package/dist/file/provider/gcs.provider.d.ts.map +1 -1
- package/dist/file/provider/gcs.provider.js +8 -9
- package/dist/file/provider/gcs.provider.js.map +1 -1
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +11 -10
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/file/provider/provider.enum.d.ts +2 -1
- package/dist/file/provider/provider.enum.d.ts.map +1 -1
- package/dist/file/provider/provider.enum.js +1 -0
- package/dist/file/provider/provider.enum.js.map +1 -1
- package/dist/file/provider/provider.factory.d.ts +1 -1
- package/dist/file/provider/provider.factory.d.ts.map +1 -1
- package/dist/file/provider/provider.factory.js +18 -5
- package/dist/file/provider/provider.factory.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +4 -20
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/file/provider/spaces.provider.d.ts +27 -0
- package/dist/file/provider/spaces.provider.d.ts.map +1 -0
- package/dist/file/provider/spaces.provider.js +203 -0
- package/dist/file/provider/spaces.provider.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/integration-profile/dto/create.dto.d.ts +9 -0
- package/dist/integration-profile/dto/create.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/create.dto.js +54 -0
- package/dist/integration-profile/dto/create.dto.js.map +1 -0
- package/dist/integration-profile/dto/export.dto.d.ts +5 -0
- package/dist/integration-profile/dto/export.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/export.dto.js +29 -0
- package/dist/integration-profile/dto/export.dto.js.map +1 -0
- package/dist/integration-profile/dto/import-confirm.dto.d.ts +17 -0
- package/dist/integration-profile/dto/import-confirm.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/import-confirm.dto.js +77 -0
- package/dist/integration-profile/dto/import-confirm.dto.js.map +1 -0
- package/dist/integration-profile/dto/update.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/update.dto.js.map +1 -0
- package/dist/integration-profile/integration-profile.controller.d.ts +142 -0
- package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.controller.js +166 -0
- package/dist/integration-profile/integration-profile.controller.js.map +1 -0
- package/dist/integration-profile/integration-profile.module.d.ts +3 -0
- package/dist/integration-profile/integration-profile.module.d.ts.map +1 -0
- package/dist/{mail-profile/mail-profile.module.js → integration-profile/integration-profile.module.js} +11 -13
- package/dist/integration-profile/integration-profile.module.js.map +1 -0
- package/dist/integration-profile/integration-profile.service.d.ts +160 -0
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.service.js +609 -0
- package/dist/integration-profile/integration-profile.service.js.map +1 -0
- package/dist/integration-profile/integration-profile.utils.d.ts +30 -0
- package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.utils.js +156 -0
- package/dist/integration-profile/integration-profile.utils.js.map +1 -0
- package/dist/mail/mail.module.d.ts.map +1 -1
- package/dist/mail/mail.module.js +36 -23
- package/dist/mail/mail.module.js.map +1 -1
- package/dist/mail/mail.service.d.ts +4 -2
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +33 -51
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
- package/dist/mcp/mcp-api-key.controller.d.ts +2 -0
- package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -1
- package/dist/mcp/mcp-api-key.controller.js +1 -1
- package/dist/mcp/mcp-api-key.controller.js.map +1 -1
- package/dist/mcp/mcp-api-key.service.d.ts +2 -1
- package/dist/mcp/mcp-api-key.service.d.ts.map +1 -1
- package/dist/mcp/mcp-api-key.service.js +6 -2
- package/dist/mcp/mcp-api-key.service.js.map +1 -1
- package/dist/mcp/mcp.module.d.ts.map +1 -1
- package/dist/mcp/mcp.module.js +3 -5
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +17 -16
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/oauth/interfaces/OAuthProvider.d.ts +1 -1
- package/dist/oauth/interfaces/OAuthProvider.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.d.ts +4 -1
- package/dist/oauth/oauth.controller.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.js +31 -5
- package/dist/oauth/oauth.controller.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +12 -1
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +125 -23
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
- package/dist/oauth/providers/facebook.provider.d.ts +5 -2
- package/dist/oauth/providers/facebook.provider.d.ts.map +1 -1
- package/dist/oauth/providers/facebook.provider.js +34 -19
- package/dist/oauth/providers/facebook.provider.js.map +1 -1
- package/dist/oauth/providers/github.provider.d.ts +6 -2
- package/dist/oauth/providers/github.provider.d.ts.map +1 -1
- package/dist/oauth/providers/github.provider.js +43 -20
- package/dist/oauth/providers/github.provider.js.map +1 -1
- package/dist/oauth/providers/google.provider.d.ts +5 -2
- package/dist/oauth/providers/google.provider.d.ts.map +1 -1
- package/dist/oauth/providers/google.provider.js +34 -19
- package/dist/oauth/providers/google.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +5 -2
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.js +43 -40
- package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft.provider.d.ts +5 -2
- package/dist/oauth/providers/microsoft.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft.provider.js +34 -19
- package/dist/oauth/providers/microsoft.provider.js.map +1 -1
- package/dist/profile/profile.controller.js +1 -1
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/security/security.service.d.ts +2 -0
- package/dist/security/security.service.d.ts.map +1 -1
- package/dist/security/security.service.js +21 -0
- package/dist/security/security.service.js.map +1 -1
- package/dist/setting/setting.service.d.ts +26 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +240 -7
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +2 -1
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.controller.js +5 -4
- package/dist/user/user.controller.js.map +1 -1
- package/dist/user/user.service.d.ts +4 -2
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +19 -4
- package/dist/user/user.service.js.map +1 -1
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts +17 -2
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -1
- package/dist/webhook-integration/dto/webhook-action.dto.js +93 -2
- package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -1
- package/dist/webhook-integration/event-webhook.controller.d.ts +1 -0
- package/dist/webhook-integration/event-webhook.controller.d.ts.map +1 -1
- package/dist/webhook-integration/event-webhook.controller.js +10 -0
- package/dist/webhook-integration/event-webhook.controller.js.map +1 -1
- package/dist/webhook-integration/event-webhook.service.d.ts +2 -0
- package/dist/webhook-integration/event-webhook.service.d.ts.map +1 -1
- package/dist/webhook-integration/event-webhook.service.js +30 -0
- package/dist/webhook-integration/event-webhook.service.js.map +1 -1
- package/dist/webhook-integration/webhook-command.registry.d.ts +15 -0
- package/dist/webhook-integration/webhook-command.registry.d.ts.map +1 -0
- package/dist/webhook-integration/webhook-command.registry.js +36 -0
- package/dist/webhook-integration/webhook-command.registry.js.map +1 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts +20 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.controller.js +48 -0
- package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.module.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.module.js +5 -0
- package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts +27 -2
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +377 -50
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/hedhog/data/file_provider.yaml +9 -1
- package/hedhog/data/integration_provider.yaml +148 -0
- package/hedhog/data/integration_type.yaml +29 -0
- package/hedhog/data/menu.yaml +6 -21
- package/hedhog/data/role.yaml +8 -0
- package/hedhog/data/route.yaml +73 -373
- package/hedhog/data/setting_group.yaml +209 -365
- package/hedhog/data/setting_subgroup.yaml +21 -13
- package/hedhog/frontend/app/account/components/connected-accounts.tsx.ejs +25 -20
- package/hedhog/frontend/app/account/components/tokens.tsx.ejs +421 -0
- package/hedhog/frontend/app/account/layout.tsx.ejs +6 -3
- package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/account/tokens/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +938 -225
- package/hedhog/frontend/app/configurations/layout.tsx.ejs +1 -1
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +3 -1
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +1830 -0
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +829 -128
- package/hedhog/frontend/app/mail/profiles/page.tsx.ejs +1 -820
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +229 -395
- package/hedhog/frontend/app/users/permissions.tsx.ejs +79 -2
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +7 -2
- package/hedhog/frontend/messages/en.json +239 -3
- package/hedhog/frontend/messages/pt.json +239 -3
- package/hedhog/table/file.yaml +1 -1
- package/hedhog/table/integration_profile.yaml +34 -0
- package/hedhog/table/integration_provider.yaml +23 -0
- package/hedhog/table/integration_type.yaml +19 -0
- package/hedhog/table/mcp_api_key.yaml +4 -0
- package/hedhog/table/webhook_action.yaml +141 -85
- package/package.json +4 -3
- package/src/ai/ai.service.ts +35 -153
- package/src/auth/guards/auth.guard.ts +32 -0
- package/src/core.module.ts +3 -3
- package/src/file/file.controller.ts +51 -42
- package/src/file/file.service.ts +67 -104
- package/src/file/provider/azure.provider.ts +14 -28
- package/src/file/provider/gcs.provider.ts +9 -9
- package/src/file/provider/local.provider.ts +10 -13
- package/src/file/provider/provider.enum.ts +1 -0
- package/src/file/provider/provider.factory.ts +21 -6
- package/src/file/provider/s3.provider.ts +4 -20
- package/src/file/provider/spaces.provider.ts +246 -0
- package/src/index.ts +6 -3
- package/src/integration-profile/dto/create.dto.ts +44 -0
- package/src/integration-profile/dto/export.dto.ts +15 -0
- package/src/integration-profile/dto/import-confirm.dto.ts +61 -0
- package/src/integration-profile/integration-profile.controller.ts +131 -0
- package/src/integration-profile/integration-profile.module.ts +16 -0
- package/src/integration-profile/integration-profile.service.ts +793 -0
- package/src/integration-profile/integration-profile.utils.ts +173 -0
- package/src/mail/mail.module.ts +41 -22
- package/src/mail/mail.service.ts +40 -64
- package/src/mcp/guards/mcp-auth.guard.ts +1 -1
- package/src/mcp/mcp-api-key.controller.ts +2 -2
- package/src/mcp/mcp-api-key.service.ts +6 -2
- package/src/mcp/mcp.module.ts +3 -5
- package/src/mcp-chat/mcp-chat.service.ts +23 -20
- package/src/oauth/interfaces/OAuthProvider.ts +1 -1
- package/src/oauth/oauth.controller.ts +30 -2
- package/src/oauth/oauth.service.ts +194 -35
- package/src/oauth/providers/abstract.provider.ts +1 -1
- package/src/oauth/providers/facebook.provider.ts +36 -20
- package/src/oauth/providers/github.provider.ts +46 -23
- package/src/oauth/providers/google.provider.ts +36 -20
- package/src/oauth/providers/microsoft-entra-id.provider.ts +42 -46
- package/src/oauth/providers/microsoft.provider.ts +36 -21
- package/src/profile/profile.controller.ts +2 -2
- package/src/security/security.service.ts +34 -1
- package/src/setting/setting.service.ts +307 -9
- package/src/user/user.controller.ts +4 -1
- package/src/user/user.service.ts +20 -2
- package/src/webhook-integration/dto/webhook-action.dto.ts +85 -4
- package/src/webhook-integration/event-webhook.controller.ts +55 -50
- package/src/webhook-integration/event-webhook.service.ts +422 -384
- package/src/webhook-integration/webhook-command.registry.ts +42 -0
- package/src/webhook-integration/webhook-integration.controller.ts +25 -0
- package/src/webhook-integration/webhook-integration.module.ts +50 -45
- package/src/webhook-integration/webhook-integration.service.ts +444 -53
- package/dist/mail-profile/dto/create.dto.d.ts +0 -23
- package/dist/mail-profile/dto/create.dto.d.ts.map +0 -1
- package/dist/mail-profile/dto/create.dto.js +0 -139
- package/dist/mail-profile/dto/create.dto.js.map +0 -1
- package/dist/mail-profile/dto/update.dto.d.ts.map +0 -1
- package/dist/mail-profile/dto/update.dto.js.map +0 -1
- package/dist/mail-profile/mail-profile.controller.d.ts +0 -94
- package/dist/mail-profile/mail-profile.controller.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.controller.js +0 -95
- package/dist/mail-profile/mail-profile.controller.js.map +0 -1
- package/dist/mail-profile/mail-profile.module.d.ts +0 -3
- package/dist/mail-profile/mail-profile.module.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.module.js.map +0 -1
- package/dist/mail-profile/mail-profile.service.d.ts +0 -109
- package/dist/mail-profile/mail-profile.service.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.service.js +0 -278
- package/dist/mail-profile/mail-profile.service.js.map +0 -1
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +0 -32
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +0 -1
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js +0 -178
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +0 -1
- package/hedhog/data/mail_profile.yaml +0 -18
- package/hedhog/table/mail_profile.yaml +0 -75
- package/src/mail-profile/dto/create.dto.ts +0 -145
- package/src/mail-profile/mail-profile.controller.ts +0 -56
- package/src/mail-profile/mail-profile.module.ts +0 -18
- package/src/mail-profile/mail-profile.service.ts +0 -308
- package/src/mcp/tools/core-mail-profile.mcp-tools.ts +0 -128
- /package/dist/{mail-profile → integration-profile}/dto/update.dto.d.ts +0 -0
- /package/dist/{mail-profile → integration-profile}/dto/update.dto.js +0 -0
- /package/src/{mail-profile → integration-profile}/dto/update.dto.ts +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { PrismaService } from '@hed-hog/api-prisma';
|
|
1
2
|
import { HttpService } from '@nestjs/axios';
|
|
2
|
-
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
|
|
3
|
+
import { BadRequestException, forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
|
|
4
|
+
import { buildOAuthConfigFromIntegration } from '../../integration-profile/integration-profile.utils';
|
|
3
5
|
import { SettingService } from '../../setting/setting.service';
|
|
4
6
|
import { BaseOAuthProvider } from './abstract.provider';
|
|
5
7
|
|
|
@@ -11,6 +13,7 @@ export class MicrosoftEntraIdProvider extends BaseOAuthProvider {
|
|
|
11
13
|
http: HttpService,
|
|
12
14
|
@Inject(forwardRef(() => SettingService))
|
|
13
15
|
private readonly setting: SettingService,
|
|
16
|
+
private readonly prisma: PrismaService,
|
|
14
17
|
) {
|
|
15
18
|
super(http);
|
|
16
19
|
}
|
|
@@ -32,39 +35,42 @@ export class MicrosoftEntraIdProvider extends BaseOAuthProvider {
|
|
|
32
35
|
return 'MICROSOFT-ENTRA-ID';
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
async
|
|
38
|
+
private async loadConfig() {
|
|
36
39
|
const settings = await this.setting.getSettingValues([
|
|
37
|
-
'
|
|
38
|
-
'microsoft_entra_id_client_secret',
|
|
39
|
-
'microsoft_entra_id_scopes',
|
|
40
|
-
'microsoft_entra_id_tenant_id',
|
|
40
|
+
'oauth-microsoft-entra-id-profile-id',
|
|
41
41
|
'url',
|
|
42
42
|
]);
|
|
43
|
+
const profileId = Number(settings['oauth-microsoft-entra-id-profile-id']);
|
|
44
|
+
if (!profileId) throw new BadRequestException('Microsoft Entra ID OAuth profile not configured.');
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
const profile = await this.prisma.integration_profile.findUnique({
|
|
47
|
+
where: { id: profileId },
|
|
48
|
+
include: { integration_provider: { select: { slug: true } } },
|
|
49
|
+
});
|
|
50
|
+
if (!profile) throw new BadRequestException('Microsoft Entra ID OAuth profile not found.');
|
|
51
|
+
|
|
52
|
+
const { clientId, clientSecret, tenantId } = buildOAuthConfigFromIntegration(
|
|
53
|
+
profile.integration_provider.slug,
|
|
54
|
+
profile.config,
|
|
55
|
+
);
|
|
56
|
+
if (!tenantId) {
|
|
57
|
+
throw new BadRequestException('Microsoft Entra ID OAuth profile is missing tenant_id.');
|
|
55
58
|
}
|
|
59
|
+
return { clientId, clientSecret, tenantId, baseUrl: String(settings['url'] ?? '') };
|
|
60
|
+
}
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
: [];
|
|
62
|
+
async getAuthUrl(callbackPath: string) {
|
|
63
|
+
const { clientId, tenantId, baseUrl } = await this.loadConfig();
|
|
64
|
+
const settings = await this.setting.getSettingValues(['oauth-microsoft-entra-id-scopes']);
|
|
65
|
+
const baseScopes: string[] = settings['oauth-microsoft-entra-id-scopes'] ?? ['openid', 'profile', 'email'];
|
|
62
66
|
const scopes = baseScopes.includes('offline_access')
|
|
63
67
|
? baseScopes
|
|
64
68
|
: [...baseScopes, 'offline_access'];
|
|
69
|
+
|
|
70
|
+
const redirectURI = this.buildRedirectUri(baseUrl, callbackPath);
|
|
65
71
|
const isConnectFlow = callbackPath.includes('/connect');
|
|
66
72
|
const params = new URLSearchParams({
|
|
67
|
-
client_id:
|
|
73
|
+
client_id: clientId,
|
|
68
74
|
redirect_uri: redirectURI,
|
|
69
75
|
response_type: 'code',
|
|
70
76
|
scope: scopes.join(' '),
|
|
@@ -75,43 +81,33 @@ export class MicrosoftEntraIdProvider extends BaseOAuthProvider {
|
|
|
75
81
|
`OAuth auth URL requested: provider=MICROSOFT-ENTRA-ID redirectUri=${redirectURI} hasOfflineAccess=${scopes.includes('offline_access') ? 'yes' : 'no'} connectFlow=${isConnectFlow ? 'yes' : 'no'} tenantConfigured=${tenantId ? 'yes' : 'no'}`,
|
|
76
82
|
);
|
|
77
83
|
|
|
78
|
-
// Force consent only for explicit account connect, not for routine login.
|
|
79
84
|
if (isConnectFlow) {
|
|
80
85
|
params.set('prompt', 'consent');
|
|
81
86
|
}
|
|
82
87
|
|
|
83
|
-
|
|
84
|
-
return authUrl;
|
|
88
|
+
return `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize?${params.toString()}`;
|
|
85
89
|
}
|
|
86
90
|
|
|
87
|
-
async getProfile(code: string, type: string): Promise<any> {
|
|
88
|
-
let
|
|
91
|
+
async getProfile(code: string, type: string, redirectUri?: string): Promise<any> {
|
|
92
|
+
let resolvedRedirectUri = '';
|
|
89
93
|
|
|
90
94
|
try {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
'url',
|
|
97
|
-
]);
|
|
98
|
-
const tenantId = settings['microsoft_entra_id_tenant_id'];
|
|
99
|
-
const scopes = settings['microsoft_entra_id_scopes'] ?? [];
|
|
100
|
-
redirectUri = this.buildRedirectUri(
|
|
101
|
-
settings['url'],
|
|
102
|
-
`/callback/microsoft-entra-id/${type}`,
|
|
103
|
-
);
|
|
95
|
+
const { clientId, clientSecret, tenantId, baseUrl } = await this.loadConfig();
|
|
96
|
+
const settings = await this.setting.getSettingValues(['oauth-microsoft-entra-id-scopes']);
|
|
97
|
+
const scopes: string[] = settings['oauth-microsoft-entra-id-scopes'] ?? [];
|
|
98
|
+
resolvedRedirectUri =
|
|
99
|
+
redirectUri?.trim() || this.buildRedirectUri(baseUrl, `/callback/microsoft-entra-id/${type}`);
|
|
104
100
|
|
|
105
101
|
this.logger.log(
|
|
106
|
-
`OAuth token exchange started: provider=MICROSOFT-ENTRA-ID type=${type} redirectUri=${
|
|
102
|
+
`OAuth token exchange started: provider=MICROSOFT-ENTRA-ID type=${type} redirectUri=${resolvedRedirectUri} hasCode=${code ? 'yes' : 'no'} codeLength=${code?.length ?? 0}`,
|
|
107
103
|
);
|
|
108
104
|
|
|
109
105
|
const token = await this.fetchToken({
|
|
110
106
|
code,
|
|
111
107
|
url: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,
|
|
112
|
-
clientId
|
|
113
|
-
clientSecret
|
|
114
|
-
redirectUri,
|
|
108
|
+
clientId,
|
|
109
|
+
clientSecret,
|
|
110
|
+
redirectUri: resolvedRedirectUri,
|
|
115
111
|
});
|
|
116
112
|
|
|
117
113
|
const profile = await this.fetchProfile(
|
|
@@ -141,7 +137,7 @@ export class MicrosoftEntraIdProvider extends BaseOAuthProvider {
|
|
|
141
137
|
const mappedError = this.mapProviderError('Microsoft Entra ID', error);
|
|
142
138
|
|
|
143
139
|
this.logger.warn(
|
|
144
|
-
`OAuth callback failed: provider=MICROSOFT-ENTRA-ID status=${mappedError.status ?? 'unknown'} error=${mappedError.providerError ?? 'unknown'} providerCode=${mappedError.providerErrorCode ?? 'n/a'} reason=${mappedError.reason} redirectUri=${
|
|
140
|
+
`OAuth callback failed: provider=MICROSOFT-ENTRA-ID status=${mappedError.status ?? 'unknown'} error=${mappedError.providerError ?? 'unknown'} providerCode=${mappedError.providerErrorCode ?? 'n/a'} reason=${mappedError.reason} redirectUri=${resolvedRedirectUri || 'unresolved'}`,
|
|
145
141
|
);
|
|
146
142
|
|
|
147
143
|
throw mappedError;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
import { PrismaService } from '@hed-hog/api-prisma';
|
|
1
2
|
import { HttpService } from '@nestjs/axios';
|
|
2
|
-
import { forwardRef, Inject, Injectable } from '@nestjs/common';
|
|
3
|
+
import { BadRequestException, forwardRef, Inject, Injectable } from '@nestjs/common';
|
|
4
|
+
import { buildOAuthConfigFromIntegration } from '../../integration-profile/integration-profile.utils';
|
|
3
5
|
import { SettingService } from '../../setting/setting.service';
|
|
4
6
|
import { BaseOAuthProvider } from './abstract.provider';
|
|
5
7
|
|
|
6
8
|
@Injectable()
|
|
7
|
-
export class MicrosoftProvider
|
|
8
|
-
extends BaseOAuthProvider {
|
|
9
|
+
export class MicrosoftProvider extends BaseOAuthProvider {
|
|
9
10
|
|
|
10
11
|
constructor(
|
|
11
12
|
http: HttpService,
|
|
12
13
|
@Inject(forwardRef(() => SettingService))
|
|
13
14
|
private readonly setting: SettingService,
|
|
15
|
+
private readonly prisma: PrismaService,
|
|
14
16
|
) {
|
|
15
17
|
super(http);
|
|
16
18
|
}
|
|
@@ -19,19 +21,35 @@ export class MicrosoftProvider
|
|
|
19
21
|
return 'MICROSOFT';
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
async
|
|
23
|
-
|
|
24
|
+
private async loadConfig() {
|
|
24
25
|
const settings = await this.setting.getSettingValues([
|
|
25
|
-
'
|
|
26
|
-
'microsoft_client_secret',
|
|
27
|
-
'microsoft_scopes',
|
|
26
|
+
'oauth-microsoft-profile-id',
|
|
28
27
|
'url',
|
|
29
28
|
]);
|
|
29
|
+
const profileId = Number(settings['oauth-microsoft-profile-id']);
|
|
30
|
+
if (!profileId) throw new BadRequestException('Microsoft OAuth profile not configured.');
|
|
31
|
+
|
|
32
|
+
const profile = await this.prisma.integration_profile.findUnique({
|
|
33
|
+
where: { id: profileId },
|
|
34
|
+
include: { integration_provider: { select: { slug: true } } },
|
|
35
|
+
});
|
|
36
|
+
if (!profile) throw new BadRequestException('Microsoft OAuth profile not found.');
|
|
37
|
+
|
|
38
|
+
const { clientId, clientSecret, tenantId } = buildOAuthConfigFromIntegration(
|
|
39
|
+
profile.integration_provider.slug,
|
|
40
|
+
profile.config,
|
|
41
|
+
);
|
|
42
|
+
return { clientId, clientSecret, tenantId, baseUrl: String(settings['url'] ?? '') };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async getAuthUrl(callbackPath: string) {
|
|
46
|
+
const { clientId, baseUrl } = await this.loadConfig();
|
|
47
|
+
const settings = await this.setting.getSettingValues(['oauth-microsoft-scopes']);
|
|
48
|
+
const scopes: string[] = settings['oauth-microsoft-scopes'] ?? ['openid', 'profile', 'email'];
|
|
49
|
+
const redirectURI = new URL(callbackPath, baseUrl).toString();
|
|
30
50
|
|
|
31
|
-
const redirectURI = new URL(callbackPath, settings['url']).toString();
|
|
32
|
-
const scopes = settings['microsoft_scopes']
|
|
33
51
|
const params = new URLSearchParams({
|
|
34
|
-
client_id:
|
|
52
|
+
client_id: clientId,
|
|
35
53
|
redirect_uri: redirectURI,
|
|
36
54
|
response_type: 'code',
|
|
37
55
|
scope: scopes.join(' '),
|
|
@@ -42,21 +60,18 @@ export class MicrosoftProvider
|
|
|
42
60
|
return `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?${params}`;
|
|
43
61
|
}
|
|
44
62
|
|
|
45
|
-
async getProfile(code: string, type: string): Promise<any> {
|
|
63
|
+
async getProfile(code: string, type: string, redirectUri?: string): Promise<any> {
|
|
64
|
+
const { clientId, clientSecret, baseUrl } = await this.loadConfig();
|
|
46
65
|
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
'microsoft_client_secret',
|
|
50
|
-
'microsoft_scopes',
|
|
51
|
-
'url',
|
|
52
|
-
]);
|
|
66
|
+
const resolvedRedirectUri =
|
|
67
|
+
redirectUri?.trim() || `${baseUrl}/callback/microsoft/${type}`;
|
|
53
68
|
|
|
54
69
|
const token = await this.fetchToken({
|
|
55
70
|
code,
|
|
56
71
|
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
|
|
57
|
-
clientId
|
|
58
|
-
clientSecret
|
|
59
|
-
redirectUri:
|
|
72
|
+
clientId,
|
|
73
|
+
clientSecret,
|
|
74
|
+
redirectUri: resolvedRedirectUri,
|
|
60
75
|
});
|
|
61
76
|
|
|
62
77
|
const profile = await this.fetchProfile(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NoRole, User } from '@hed-hog/api';
|
|
2
2
|
import { Locale } from '@hed-hog/api-locale';
|
|
3
3
|
import { Body, Controller, Delete, Get, Headers, Ip, Param, ParseIntPipe, Post, Put, UploadedFile, UseInterceptors } from '@nestjs/common';
|
|
4
4
|
import { FileInterceptor } from '@nestjs/platform-express';
|
|
@@ -19,7 +19,7 @@ import { VerifyMfaTotpDto } from './dto/verify-mfa-totp.dto';
|
|
|
19
19
|
import { VerifyWebAuthnRegistrationDto } from './dto/verify-webauthn-registration.dto';
|
|
20
20
|
import { VerifyWebAuthnDto } from './dto/verify-webauthn.dto';
|
|
21
21
|
import { ProfileService } from './profile.service';
|
|
22
|
-
@
|
|
22
|
+
@NoRole()
|
|
23
23
|
@Controller('profile')
|
|
24
24
|
export class ProfileController {
|
|
25
25
|
|
|
@@ -2,7 +2,15 @@ import { getLocaleText } from '@hed-hog/api-locale';
|
|
|
2
2
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
|
3
3
|
import { ConfigService } from '@nestjs/config';
|
|
4
4
|
import * as argon2 from 'argon2';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createCipheriv,
|
|
7
|
+
createDecipheriv,
|
|
8
|
+
createHash,
|
|
9
|
+
createHmac,
|
|
10
|
+
randomBytes,
|
|
11
|
+
scryptSync,
|
|
12
|
+
timingSafeEqual,
|
|
13
|
+
} from 'crypto';
|
|
6
14
|
|
|
7
15
|
@Injectable()
|
|
8
16
|
export class SecurityService {
|
|
@@ -31,6 +39,31 @@ export class SecurityService {
|
|
|
31
39
|
return createHash('sha256').update(value).digest('base64url');
|
|
32
40
|
}
|
|
33
41
|
|
|
42
|
+
signHmacSha256(value: string, secret?: string): string {
|
|
43
|
+
const signingSecret = secret || this.getJwtSecret();
|
|
44
|
+
return createHmac('sha256', signingSecret).update(value).digest('base64url');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
verifyHmacSha256(value: string, signature: string, secret?: string): boolean {
|
|
48
|
+
if (!signature) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const expected = this.signHmacSha256(value, secret);
|
|
54
|
+
const expectedBuffer = Buffer.from(expected);
|
|
55
|
+
const providedBuffer = Buffer.from(signature);
|
|
56
|
+
|
|
57
|
+
if (expectedBuffer.length !== providedBuffer.length) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return timingSafeEqual(expectedBuffer, providedBuffer);
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
34
67
|
hashArgon2(value: string, pepper?: string): Promise<string> {
|
|
35
68
|
return argon2.hash(this.getValueWithPepper(value, pepper));
|
|
36
69
|
}
|