@hed-hog/core 0.0.398 → 0.0.400
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-agent.sort.d.ts +6 -0
- package/dist/ai/ai-agent.sort.d.ts.map +1 -0
- package/dist/ai/ai-agent.sort.js +21 -0
- package/dist/ai/ai-agent.sort.js.map +1 -0
- package/dist/ai/ai.controller.d.ts +4 -4
- package/dist/ai/ai.service.d.ts +35 -4
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +51 -137
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -1
- package/dist/ai-instruction/ai-instruction.service.js +26 -23
- package/dist/ai-instruction/ai-instruction.service.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.sort.d.ts +16 -0
- package/dist/ai-instruction/ai-instruction.sort.d.ts.map +1 -0
- package/dist/ai-instruction/ai-instruction.sort.js +32 -0
- package/dist/ai-instruction/ai-instruction.sort.js.map +1 -0
- package/dist/auth/auth.controller.d.ts +24 -8
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.module.d.ts.map +1 -1
- package/dist/auth/auth.module.js +8 -1
- package/dist/auth/auth.module.js.map +1 -1
- package/dist/auth/auth.service.d.ts +72 -25
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +41 -4
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/auth/guards/auth.guard.d.ts +3 -1
- package/dist/auth/guards/auth.guard.d.ts.map +1 -1
- package/dist/auth/guards/auth.guard.js +12 -3
- package/dist/auth/guards/auth.guard.js.map +1 -1
- package/dist/authorize/authorize.controller.d.ts +30 -6
- package/dist/authorize/authorize.controller.d.ts.map +1 -1
- package/dist/authorize/authorize.controller.js +120 -13
- package/dist/authorize/authorize.controller.js.map +1 -1
- package/dist/authorize/authorize.errors.d.ts +34 -0
- package/dist/authorize/authorize.errors.d.ts.map +1 -0
- package/dist/authorize/authorize.errors.js +37 -0
- package/dist/authorize/authorize.errors.js.map +1 -0
- package/dist/authorize/authorize.module.d.ts.map +1 -1
- package/dist/authorize/authorize.module.js +6 -1
- package/dist/authorize/authorize.module.js.map +1 -1
- package/dist/authorize/authorize.service.d.ts +78 -4
- package/dist/authorize/authorize.service.d.ts.map +1 -1
- package/dist/authorize/authorize.service.js +212 -21
- package/dist/authorize/authorize.service.js.map +1 -1
- package/dist/authorize/dto/authorize-info.dto.d.ts +10 -1
- package/dist/authorize/dto/authorize-info.dto.d.ts.map +1 -1
- package/dist/authorize/dto/authorize-info.dto.js +16 -1
- package/dist/authorize/dto/authorize-info.dto.js.map +1 -1
- package/dist/authorize/dto/consent.dto.d.ts +10 -1
- package/dist/authorize/dto/consent.dto.d.ts.map +1 -1
- package/dist/authorize/dto/consent.dto.js +16 -1
- package/dist/authorize/dto/consent.dto.js.map +1 -1
- package/dist/authorize/dto/token.dto.d.ts +12 -0
- package/dist/authorize/dto/token.dto.d.ts.map +1 -1
- package/dist/authorize/dto/token.dto.js +21 -1
- package/dist/authorize/dto/token.dto.js.map +1 -1
- package/dist/authorize/oauth-exception.filter.d.ts +17 -0
- package/dist/authorize/oauth-exception.filter.d.ts.map +1 -0
- package/dist/authorize/oauth-exception.filter.js +54 -0
- package/dist/authorize/oauth-exception.filter.js.map +1 -0
- package/dist/authorize/oauth-metadata.service.d.ts +39 -0
- package/dist/authorize/oauth-metadata.service.d.ts.map +1 -0
- package/dist/authorize/oauth-metadata.service.js +81 -0
- package/dist/authorize/oauth-metadata.service.js.map +1 -0
- package/dist/authorize/well-known.controller.d.ts +67 -0
- package/dist/authorize/well-known.controller.d.ts.map +1 -0
- package/dist/authorize/well-known.controller.js +126 -0
- package/dist/authorize/well-known.controller.js.map +1 -0
- package/dist/captcha/captcha.service.d.ts +32 -2
- package/dist/captcha/captcha.service.d.ts.map +1 -1
- package/dist/captcha/captcha.service.js +85 -12
- package/dist/captcha/captcha.service.js.map +1 -1
- package/dist/challenge/challenge.service.d.ts +2 -2
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +6 -0
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard/dashboard.controller.d.ts +9 -9
- package/dist/dashboard/dashboard/dashboard.service.d.ts +9 -9
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +3 -3
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +3 -3
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.js +2 -4
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.js.map +1 -1
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.d.ts +8 -0
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.d.ts.map +1 -0
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.js +18 -0
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.js.map +1 -0
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.service.js +2 -4
- package/dist/dashboard/dashboard-item/dashboard-item.service.js.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.sort.d.ts +9 -0
- package/dist/dashboard/dashboard-item/dashboard-item.sort.d.ts.map +1 -0
- package/dist/dashboard/dashboard-item/dashboard-item.sort.js +19 -0
- package/dist/dashboard/dashboard-item/dashboard-item.sort.js.map +1 -0
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +3 -3
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.service.js +2 -4
- package/dist/dashboard/dashboard-role/dashboard-role.service.js.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.sort.d.ts +8 -0
- package/dist/dashboard/dashboard-role/dashboard-role.sort.d.ts.map +1 -0
- package/dist/dashboard/dashboard-role/dashboard-role.sort.js +16 -0
- package/dist/dashboard/dashboard-role/dashboard-role.sort.js.map +1 -0
- package/dist/file/file-upload-ticket.service.d.ts +160 -0
- package/dist/file/file-upload-ticket.service.d.ts.map +1 -0
- package/dist/file/file-upload-ticket.service.js +382 -0
- package/dist/file/file-upload-ticket.service.js.map +1 -0
- package/dist/file/file.controller.d.ts +24 -1
- package/dist/file/file.controller.d.ts.map +1 -1
- package/dist/file/file.controller.js +63 -2
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.module.d.ts.map +1 -1
- package/dist/file/file.module.js +14 -2
- package/dist/file/file.module.js.map +1 -1
- package/dist/file/file.service.d.ts +182 -6
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +385 -36
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/filename-encoding.util.d.ts +24 -0
- package/dist/file/filename-encoding.util.d.ts.map +1 -0
- package/dist/file/filename-encoding.util.js +63 -0
- package/dist/file/filename-encoding.util.js.map +1 -0
- package/dist/file/image-optimization.service.d.ts +27 -0
- package/dist/file/image-optimization.service.d.ts.map +1 -1
- package/dist/file/image-optimization.service.js +63 -14
- package/dist/file/image-optimization.service.js.map +1 -1
- package/dist/file/mcp-file-source.schema.d.ts +33 -0
- package/dist/file/mcp-file-source.schema.d.ts.map +1 -0
- package/dist/file/mcp-file-source.schema.js +75 -0
- package/dist/file/mcp-file-source.schema.js.map +1 -0
- package/dist/file/mcp-file-source.service.d.ts +124 -0
- package/dist/file/mcp-file-source.service.d.ts.map +1 -0
- package/dist/file/mcp-file-source.service.js +262 -0
- package/dist/file/mcp-file-source.service.js.map +1 -0
- package/dist/file/mimetype-sniff.util.d.ts +62 -0
- package/dist/file/mimetype-sniff.util.d.ts.map +1 -0
- package/dist/file/mimetype-sniff.util.js +226 -0
- package/dist/file/mimetype-sniff.util.js.map +1 -0
- package/dist/file/remote-fetch.util.d.ts +35 -0
- package/dist/file/remote-fetch.util.d.ts.map +1 -0
- package/dist/file/remote-fetch.util.js +236 -0
- package/dist/file/remote-fetch.util.js.map +1 -0
- package/dist/impersonation/dto/start-impersonation.dto.d.ts +4 -1
- package/dist/impersonation/dto/start-impersonation.dto.d.ts.map +1 -1
- package/dist/impersonation/dto/start-impersonation.dto.js +1 -1
- package/dist/impersonation/dto/start-impersonation.dto.js.map +1 -1
- package/dist/impersonation/impersonation.service.d.ts +8 -3
- package/dist/impersonation/impersonation.service.d.ts.map +1 -1
- package/dist/impersonation/impersonation.service.js +14 -4
- package/dist/impersonation/impersonation.service.js.map +1 -1
- package/dist/incident/incident.controller.d.ts +2 -1
- package/dist/incident/incident.controller.d.ts.map +1 -1
- package/dist/incident/incident.controller.js +10 -6
- package/dist/incident/incident.controller.js.map +1 -1
- package/dist/incident/incident.service.d.ts +2 -0
- package/dist/incident/incident.service.d.ts.map +1 -1
- package/dist/incident/incident.service.js +4 -0
- package/dist/incident/incident.service.js.map +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.js +7 -0
- package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
- package/dist/integration-profile/integration-profile.service.d.ts +0 -13
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.service.js +5 -40
- package/dist/integration-profile/integration-profile.service.js.map +1 -1
- package/dist/integration-profile/integration-profile.utils.js +5 -5
- package/dist/integration-profile/integration-profile.utils.js.map +1 -1
- package/dist/integration-profile/testers/index.d.ts.map +1 -1
- package/dist/integration-profile/testers/index.js +2 -0
- package/dist/integration-profile/testers/index.js.map +1 -1
- package/dist/integration-profile/testers/shipping.testers.d.ts +3 -0
- package/dist/integration-profile/testers/shipping.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/shipping.testers.js +71 -0
- package/dist/integration-profile/testers/shipping.testers.js.map +1 -0
- package/dist/locale/locale.controller.d.ts +1 -1
- package/dist/locale/locale.service.d.ts +1 -1
- package/dist/mail/dto/send.dto.d.ts +6 -1
- package/dist/mail/dto/send.dto.d.ts.map +1 -1
- package/dist/mail/dto/send.dto.js.map +1 -1
- package/dist/mail/mail.service.d.ts +9 -0
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +34 -14
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mail-sent/mail-sent.controller.d.ts +1 -1
- package/dist/mail-sent/mail-sent.service.d.ts +1 -1
- package/dist/mail-sent/mail-sent.service.d.ts.map +1 -1
- package/dist/mail-sent/mail-sent.service.js +2 -1
- package/dist/mail-sent/mail-sent.service.js.map +1 -1
- package/dist/mail-sent/mail-sent.sort.d.ts +9 -0
- package/dist/mail-sent/mail-sent.sort.d.ts.map +1 -0
- package/dist/mail-sent/mail-sent.sort.js +19 -0
- package/dist/mail-sent/mail-sent.sort.js.map +1 -0
- package/dist/mcp/filters/mcp-challenge.filter.d.ts +20 -0
- package/dist/mcp/filters/mcp-challenge.filter.d.ts.map +1 -0
- package/dist/mcp/filters/mcp-challenge.filter.js +69 -0
- package/dist/mcp/filters/mcp-challenge.filter.js.map +1 -0
- package/dist/mcp/guards/mcp-auth.guard.d.ts +4 -1
- package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js +19 -5
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
- package/dist/mcp/guards/mcp-permission.guard.d.ts +25 -3
- package/dist/mcp/guards/mcp-permission.guard.d.ts.map +1 -1
- package/dist/mcp/guards/mcp-permission.guard.js +46 -26
- package/dist/mcp/guards/mcp-permission.guard.js.map +1 -1
- package/dist/mcp/mcp-audit.service.d.ts +17 -0
- package/dist/mcp/mcp-audit.service.d.ts.map +1 -1
- package/dist/mcp/mcp-audit.service.js +32 -3
- package/dist/mcp/mcp-audit.service.js.map +1 -1
- package/dist/mcp/mcp-permission.service.d.ts +64 -0
- package/dist/mcp/mcp-permission.service.d.ts.map +1 -0
- package/dist/mcp/mcp-permission.service.js +178 -0
- package/dist/mcp/mcp-permission.service.js.map +1 -0
- package/dist/mcp/mcp-server.service.d.ts +3 -1
- package/dist/mcp/mcp-server.service.d.ts.map +1 -1
- package/dist/mcp/mcp-server.service.js +36 -15
- package/dist/mcp/mcp-server.service.js.map +1 -1
- package/dist/mcp/mcp.controller.d.ts.map +1 -1
- package/dist/mcp/mcp.controller.js +10 -2
- package/dist/mcp/mcp.controller.js.map +1 -1
- package/dist/mcp/mcp.module.d.ts.map +1 -1
- package/dist/mcp/mcp.module.js +5 -1
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/mcp/tools/core-ai.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-ai.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js +1 -1
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-dashboard.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-dashboard.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js +2 -10
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-files.mcp-tools.d.ts +17 -5
- package/dist/mcp/tools/core-files.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-files.mcp-tools.js +186 -24
- package/dist/mcp/tools/core-files.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-integration-events.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-integration-events.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js +2 -14
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-mail.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-mail.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-menus.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-menus.mcp-tools.js +2 -10
- package/dist/mcp/tools/core-menus.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-notifications.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-notifications.mcp-tools.js +0 -1
- package/dist/mcp/tools/core-notifications.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-roles.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-roles.mcp-tools.js +2 -13
- package/dist/mcp/tools/core-roles.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-routes.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-routes.mcp-tools.js +2 -11
- package/dist/mcp/tools/core-routes.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-screens.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-screens.mcp-tools.js +2 -11
- package/dist/mcp/tools/core-screens.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-sessions.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-sessions.mcp-tools.js +0 -2
- package/dist/mcp/tools/core-sessions.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-settings.mcp-tools.js +2 -10
- package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-users.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-users.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-webhooks.mcp-tools.js +2 -10
- package/dist/mcp/tools/core-webhooks.mcp-tools.js.map +1 -1
- package/dist/mcp/types/mcp-context.type.d.ts +9 -0
- package/dist/mcp/types/mcp-context.type.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +8 -0
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/meeting/meeting-provider.registry.d.ts +115 -0
- package/dist/meeting/meeting-provider.registry.d.ts.map +1 -1
- package/dist/meeting/meeting-provider.registry.js.map +1 -1
- package/dist/meeting/meeting.constants.d.ts +70 -0
- package/dist/meeting/meeting.constants.d.ts.map +1 -1
- package/dist/meeting/meeting.constants.js +9 -1
- package/dist/meeting/meeting.constants.js.map +1 -1
- package/dist/menu/menu.service.d.ts.map +1 -1
- package/dist/menu/menu.service.js +29 -9
- package/dist/menu/menu.service.js.map +1 -1
- package/dist/message-template/dto/update-message-template.dto.d.ts +18 -0
- package/dist/message-template/dto/update-message-template.dto.d.ts.map +1 -0
- package/dist/message-template/dto/update-message-template.dto.js +38 -0
- package/dist/message-template/dto/update-message-template.dto.js.map +1 -0
- package/dist/message-template/message-template-admin.service.d.ts +70 -0
- package/dist/message-template/message-template-admin.service.d.ts.map +1 -0
- package/dist/message-template/message-template-admin.service.js +226 -0
- package/dist/message-template/message-template-admin.service.js.map +1 -0
- package/dist/message-template/message-template.controller.d.ts +29 -0
- package/dist/message-template/message-template.controller.d.ts.map +1 -0
- package/dist/message-template/message-template.controller.js +101 -0
- package/dist/message-template/message-template.controller.js.map +1 -0
- package/dist/message-template/message-template.module.d.ts +10 -0
- package/dist/message-template/message-template.module.d.ts.map +1 -0
- package/dist/message-template/message-template.module.js +33 -0
- package/dist/message-template/message-template.module.js.map +1 -0
- package/dist/message-template/message-template.registry.d.ts +55 -0
- package/dist/message-template/message-template.registry.d.ts.map +1 -0
- package/dist/message-template/message-template.registry.js +64 -0
- package/dist/message-template/message-template.registry.js.map +1 -0
- package/dist/message-template/message-template.service.d.ts +59 -0
- package/dist/message-template/message-template.service.d.ts.map +1 -0
- package/dist/message-template/message-template.service.js +166 -0
- package/dist/message-template/message-template.service.js.map +1 -0
- package/dist/notification/notification.constants.d.ts +11 -0
- package/dist/notification/notification.constants.d.ts.map +1 -0
- package/dist/notification/notification.constants.js +14 -0
- package/dist/notification/notification.constants.js.map +1 -0
- package/dist/notification/notification.controller.d.ts +20 -20
- package/dist/notification/notification.module.d.ts.map +1 -1
- package/dist/notification/notification.module.js +3 -0
- package/dist/notification/notification.module.js.map +1 -1
- package/dist/notification/notification.service.d.ts +33 -21
- package/dist/notification/notification.service.d.ts.map +1 -1
- package/dist/notification/notification.service.js +36 -2
- package/dist/notification/notification.service.js.map +1 -1
- package/dist/oauth/oauth.controller.d.ts +4 -6
- package/dist/oauth/oauth.controller.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.js +0 -1
- package/dist/oauth/oauth.controller.js.map +1 -1
- package/dist/oauth/oauth.errors.d.ts +15 -1
- package/dist/oauth/oauth.errors.d.ts.map +1 -1
- package/dist/oauth/oauth.errors.js +9 -1
- package/dist/oauth/oauth.errors.js.map +1 -1
- package/dist/oauth/oauth.module.d.ts.map +1 -1
- package/dist/oauth/oauth.module.js +6 -1
- package/dist/oauth/oauth.module.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +25 -5
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +63 -27
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts +10 -0
- package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
- package/dist/oauth/providers/abstract.provider.js +39 -12
- package/dist/oauth/providers/abstract.provider.js.map +1 -1
- package/dist/oauth/providers/github.provider.d.ts +1 -1
- package/dist/oauth/providers/github.provider.d.ts.map +1 -1
- package/dist/oauth/providers/github.provider.js +48 -22
- package/dist/oauth/providers/github.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.js +6 -0
- package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
- package/dist/observability/monitored-cron.d.ts +29 -12
- package/dist/observability/monitored-cron.d.ts.map +1 -1
- package/dist/observability/monitored-cron.js +131 -46
- package/dist/observability/monitored-cron.js.map +1 -1
- package/dist/pairing/pairing.controller.d.ts +9 -9
- package/dist/pairing/pairing.service.d.ts +15 -11
- package/dist/pairing/pairing.service.d.ts.map +1 -1
- package/dist/profile/dto/change-password.dto.d.ts.map +1 -1
- package/dist/profile/dto/change-password.dto.js +4 -6
- package/dist/profile/dto/change-password.dto.js.map +1 -1
- package/dist/profile/profile.controller.d.ts +1 -1
- package/dist/profile/profile.service.d.ts +1 -1
- package/dist/profile/profile.service.d.ts.map +1 -1
- package/dist/profile/profile.service.js +9 -3
- package/dist/profile/profile.service.js.map +1 -1
- package/dist/realtime/realtime-tick.coalescer.d.ts +34 -0
- package/dist/realtime/realtime-tick.coalescer.d.ts.map +1 -0
- package/dist/realtime/realtime-tick.coalescer.js +60 -0
- package/dist/realtime/realtime-tick.coalescer.js.map +1 -0
- package/dist/realtime/realtime.service.d.ts +2 -0
- package/dist/realtime/realtime.service.d.ts.map +1 -1
- package/dist/realtime/realtime.service.js +22 -2
- package/dist/realtime/realtime.service.js.map +1 -1
- package/dist/redis/redis-kv.service.d.ts +90 -0
- package/dist/redis/redis-kv.service.d.ts.map +1 -0
- package/dist/redis/redis-kv.service.js +247 -0
- package/dist/redis/redis-kv.service.js.map +1 -0
- package/dist/redis/redis-master.d.ts +29 -0
- package/dist/redis/redis-master.d.ts.map +1 -0
- package/dist/redis/redis-master.js +81 -0
- package/dist/redis/redis-master.js.map +1 -0
- package/dist/redis/redis-pubsub.d.ts +12 -0
- package/dist/redis/redis-pubsub.d.ts.map +1 -1
- package/dist/redis/redis-pubsub.js +25 -2
- package/dist/redis/redis-pubsub.js.map +1 -1
- package/dist/redis/redis.module.d.ts +11 -0
- package/dist/redis/redis.module.d.ts.map +1 -0
- package/dist/redis/redis.module.js +30 -0
- package/dist/redis/redis.module.js.map +1 -0
- package/dist/session/session.controller.d.ts +6 -2
- package/dist/session/session.controller.d.ts.map +1 -1
- package/dist/session/session.service.d.ts +118 -15
- package/dist/session/session.service.d.ts.map +1 -1
- package/dist/session/session.service.js +251 -77
- package/dist/session/session.service.js.map +1 -1
- package/dist/setting/setting.controller.d.ts +5 -0
- package/dist/setting/setting.controller.d.ts.map +1 -1
- package/dist/setting/setting.service.d.ts +7 -0
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +38 -3
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/task/task.service.d.ts +17 -0
- package/dist/task/task.service.d.ts.map +1 -1
- package/dist/task/task.service.js +48 -13
- package/dist/task/task.service.js.map +1 -1
- package/dist/token/token.service.d.ts +19 -1
- package/dist/token/token.service.d.ts.map +1 -1
- package/dist/token/token.service.js +39 -2
- package/dist/token/token.service.js.map +1 -1
- package/dist/user/user-credential.util.d.ts +10 -0
- package/dist/user/user-credential.util.d.ts.map +1 -1
- package/dist/user/user-credential.util.js +14 -1
- package/dist/user/user-credential.util.js.map +1 -1
- package/dist/user/user.service.d.ts +12 -4
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +2 -11
- package/dist/user/user.service.js.map +1 -1
- package/dist/user/user.sort.d.ts +16 -0
- package/dist/user/user.sort.d.ts.map +1 -0
- package/dist/user/user.sort.js +25 -0
- package/dist/user/user.sort.js.map +1 -0
- package/dist/utils/abbreviate-name.d.ts +13 -0
- package/dist/utils/abbreviate-name.d.ts.map +1 -0
- package/dist/utils/abbreviate-name.js +42 -0
- package/dist/utils/abbreviate-name.js.map +1 -0
- package/dist/utils/date-range-query.dto.d.ts +11 -0
- package/dist/utils/date-range-query.dto.d.ts.map +1 -0
- package/dist/utils/date-range-query.dto.js +63 -0
- package/dist/utils/date-range-query.dto.js.map +1 -0
- package/dist/utils/date-range.d.ts +96 -0
- package/dist/utils/date-range.d.ts.map +1 -0
- package/dist/utils/date-range.js +172 -0
- package/dist/utils/date-range.js.map +1 -0
- package/dist/webhook-integration/webhook-utils.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-utils.js +24 -0
- package/dist/webhook-integration/webhook-utils.js.map +1 -1
- package/dist/whatsapp-sender/whatsapp-recipients.d.ts +49 -0
- package/dist/whatsapp-sender/whatsapp-recipients.d.ts.map +1 -0
- package/dist/whatsapp-sender/whatsapp-recipients.js +66 -0
- package/dist/whatsapp-sender/whatsapp-recipients.js.map +1 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +25 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -1
- package/dist/whatsapp-sender/whatsapp-sender.service.js +46 -5
- package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -1
- package/hedhog/data/integration_provider.yaml +9 -0
- package/hedhog/data/integration_type.yaml +6 -0
- package/hedhog/data/locale.yaml +0 -1
- package/hedhog/data/mail.yaml +2 -2
- package/hedhog/data/mail_layout.yaml +6 -3
- package/hedhog/data/menu.yaml +25 -5
- package/hedhog/data/route.yaml +140 -0
- package/hedhog/data/setting_group.yaml +137 -3
- package/hedhog/frontend/app/access-log/page.tsx.ejs +47 -53
- package/hedhog/frontend/app/account/components/active-sessions.tsx.ejs +33 -8
- package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +54 -13
- package/hedhog/frontend/app/account/components/mfa-method-card.tsx.ejs +7 -1
- package/hedhog/frontend/app/account/components/recovery-codes-dialog.tsx.ejs +1 -0
- package/hedhog/frontend/app/account/components/tokens.tsx.ejs +47 -17
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +46 -5
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +101 -30
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +24 -8
- package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +80 -15
- package/hedhog/frontend/app/configurations/[slug]/components/image-optimization-action.tsx.ejs +166 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.test.tsx.ejs +145 -45
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +99 -219
- package/hedhog/frontend/app/configurations/[slug]/page.tsx.ejs +19 -1
- package/hedhog/frontend/app/configurations/layout.tsx.ejs +19 -5
- package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +2 -8
- package/hedhog/frontend/app/dashboard/components/dynamic-widget.tsx.ejs +3 -0
- package/hedhog/frontend/app/dashboard/components/widget-wrapper.tsx.ejs +4 -0
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +43 -44
- package/hedhog/frontend/app/dashboard/management/tabs/component-roles-tab.tsx.ejs +41 -3
- package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +42 -2
- package/hedhog/frontend/app/dashboard/management/tabs/dashboard-roles-tab.tsx.ejs +41 -3
- package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +39 -4
- package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +42 -3
- package/hedhog/frontend/app/incidents/page.tsx.ejs +60 -31
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +45 -5
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +92 -15
- package/hedhog/frontend/app/mail/log/page.tsx.ejs +109 -61
- package/hedhog/frontend/app/mail/template/page.tsx.ejs +125 -23
- package/hedhog/frontend/app/mcp_chat/chat-components.tsx.ejs +13 -15
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +116 -110
- package/hedhog/frontend/app/message-templates/_components/message-template-sheet.tsx.ejs +245 -0
- package/hedhog/frontend/app/message-templates/_lib/types.ts.ejs +24 -0
- package/hedhog/frontend/app/message-templates/page.tsx.ejs +182 -0
- package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1 -0
- package/hedhog/frontend/app/pages/page.tsx.ejs +94 -9
- package/hedhog/frontend/app/roles/menus.tsx.ejs +4 -4
- package/hedhog/frontend/app/roles/routes.tsx.ejs +4 -4
- package/hedhog/frontend/app/roles/users.tsx.ejs +4 -4
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +71 -9
- package/hedhog/frontend/app/users/page.tsx.ejs +77 -67
- package/hedhog/frontend/messages/en.json +183 -36
- package/hedhog/frontend/messages/pt.json +183 -36
- package/hedhog/table/cron_lock.yaml +17 -0
- package/hedhog/table/file.yaml +13 -1
- package/hedhog/table/file_upload_chunk.yaml +23 -0
- package/hedhog/table/file_upload_ticket.yaml +67 -0
- package/hedhog/table/mcp_tool_call_log.yaml +30 -22
- package/hedhog/table/message_template.yaml +33 -0
- package/hedhog/table/setting.yaml +8 -0
- package/hedhog/table/user_session.yaml +36 -1
- package/package.json +8 -6
- package/src/ai/ai-agent.sort.ts +21 -0
- package/src/ai/ai.service.spec.ts +173 -1
- package/src/ai/ai.service.ts +64 -193
- package/src/ai-instruction/ai-instruction.service.ts +32 -28
- package/src/ai-instruction/ai-instruction.sort.ts +32 -0
- package/src/auth/auth.module.ts +8 -1
- package/src/auth/auth.service.spec.ts +108 -1
- package/src/auth/auth.service.ts +59 -5
- package/src/auth/guards/auth.guard.ts +9 -1
- package/src/authorize/authorize.controller.ts +126 -11
- package/src/authorize/authorize.errors.ts +55 -0
- package/src/authorize/authorize.module.ts +6 -1
- package/src/authorize/authorize.service.spec.ts +379 -7
- package/src/authorize/authorize.service.ts +309 -23
- package/src/authorize/dto/authorize-info.dto.ts +21 -3
- package/src/authorize/dto/consent.dto.ts +21 -3
- package/src/authorize/dto/token.dto.ts +24 -2
- package/src/authorize/oauth-exception.filter.ts +58 -0
- package/src/authorize/oauth-metadata.service.ts +67 -0
- package/src/authorize/well-known.controller.spec.ts +84 -0
- package/src/authorize/well-known.controller.ts +96 -0
- package/src/captcha/captcha.service.spec.ts +211 -4
- package/src/captcha/captcha.service.ts +127 -10
- package/src/core.module.ts +6 -0
- package/src/dashboard/dashboard-component-role/dashboard-component-role.service.ts +2 -3
- package/src/dashboard/dashboard-component-role/dashboard-component-role.sort.ts +18 -0
- package/src/dashboard/dashboard-item/dashboard-item.service.ts +2 -3
- package/src/dashboard/dashboard-item/dashboard-item.sort.ts +19 -0
- package/src/dashboard/dashboard-role/dashboard-role.service.ts +2 -3
- package/src/dashboard/dashboard-role/dashboard-role.sort.ts +16 -0
- package/src/file/file-upload-ticket.service.spec.ts +422 -0
- package/src/file/file-upload-ticket.service.ts +513 -0
- package/src/file/file.controller.ts +65 -0
- package/src/file/file.module.ts +14 -2
- package/src/file/file.service.spec.ts +94 -0
- package/src/file/file.service.ts +432 -30
- package/src/file/filename-encoding.util.spec.ts +54 -0
- package/src/file/filename-encoding.util.ts +67 -0
- package/src/file/image-optimization.service.spec.ts +156 -19
- package/src/file/image-optimization.service.ts +106 -21
- package/src/file/mcp-file-source.schema.ts +83 -0
- package/src/file/mcp-file-source.service.spec.ts +473 -0
- package/src/file/mcp-file-source.service.ts +445 -0
- package/src/file/mimetype-sniff.util.spec.ts +126 -0
- package/src/file/mimetype-sniff.util.ts +265 -0
- package/src/file/remote-fetch.util.spec.ts +117 -0
- package/src/file/remote-fetch.util.ts +330 -0
- package/src/impersonation/dto/start-impersonation.dto.ts +5 -2
- package/src/impersonation/impersonation.service.spec.ts +24 -1
- package/src/impersonation/impersonation.service.ts +14 -4
- package/src/incident/incident.controller.ts +9 -1
- package/src/incident/incident.service.ts +7 -0
- package/src/index.ts +17 -0
- package/src/integration-profile/integration-profile.secrets.ts +7 -0
- package/src/integration-profile/integration-profile.service.ts +7 -64
- package/src/integration-profile/integration-profile.utils.spec.ts +9 -0
- package/src/integration-profile/integration-profile.utils.ts +5 -5
- package/src/integration-profile/testers/index.ts +2 -0
- package/src/integration-profile/testers/remaining.testers.spec.ts +79 -0
- package/src/integration-profile/testers/shipping.testers.ts +94 -0
- package/src/mail/dto/send.dto.ts +6 -1
- package/src/mail/mail-template.spec.ts +58 -1
- package/src/mail/mail.service.spec.ts +112 -0
- package/src/mail/mail.service.ts +42 -4
- package/src/mail-sent/mail-sent.service.ts +3 -0
- package/src/mail-sent/mail-sent.sort.ts +19 -0
- package/src/mcp/filters/mcp-challenge.filter.spec.ts +76 -0
- package/src/mcp/filters/mcp-challenge.filter.ts +70 -0
- package/src/mcp/guards/mcp-auth.guard.spec.ts +51 -2
- package/src/mcp/guards/mcp-auth.guard.ts +24 -1
- package/src/mcp/guards/mcp-permission.guard.spec.ts +109 -15
- package/src/mcp/guards/mcp-permission.guard.ts +76 -51
- package/src/mcp/mcp-audit.service.spec.ts +107 -0
- package/src/mcp/mcp-audit.service.ts +37 -1
- package/src/mcp/mcp-permission.service.spec.ts +197 -0
- package/src/mcp/mcp-permission.service.ts +184 -0
- package/src/mcp/mcp-server.service.spec.ts +84 -2
- package/src/mcp/mcp-server.service.ts +111 -87
- package/src/mcp/mcp.controller.ts +8 -1
- package/src/mcp/mcp.module.ts +5 -1
- package/src/mcp/tools/core-ai.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-dashboard-items.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-dashboard.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-event-webhooks.mcp-tools.ts +1 -2
- package/src/mcp/tools/core-files.mcp-tools.ts +202 -22
- package/src/mcp/tools/core-integration-events.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-mail-sent.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-mail.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-menus.mcp-tools.ts +1 -2
- package/src/mcp/tools/core-notifications.mcp-tools.ts +0 -1
- package/src/mcp/tools/core-roles.mcp-tools.ts +1 -5
- package/src/mcp/tools/core-routes.mcp-tools.ts +1 -3
- package/src/mcp/tools/core-screens.mcp-tools.ts +1 -3
- package/src/mcp/tools/core-sessions.mcp-tools.ts +0 -2
- package/src/mcp/tools/core-settings.mcp-tools.ts +1 -2
- package/src/mcp/tools/core-users.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-webhooks.mcp-tools.ts +1 -2
- package/src/mcp/types/mcp-context.type.ts +15 -6
- package/src/mcp-chat/mcp-chat.service.ts +8 -0
- package/src/meeting/meeting-provider.registry.ts +121 -0
- package/src/meeting/meeting.constants.ts +74 -0
- package/src/menu/menu.service.spec.ts +89 -0
- package/src/menu/menu.service.ts +29 -11
- package/src/message-template/dto/update-message-template.dto.ts +22 -0
- package/src/message-template/message-template-admin.service.spec.ts +163 -0
- package/src/message-template/message-template-admin.service.ts +239 -0
- package/src/message-template/message-template.controller.ts +52 -0
- package/src/message-template/message-template.module.ts +21 -0
- package/src/message-template/message-template.registry.spec.ts +62 -0
- package/src/message-template/message-template.registry.ts +125 -0
- package/src/message-template/message-template.service.spec.ts +149 -0
- package/src/message-template/message-template.service.ts +149 -0
- package/src/notification/notification.constants.ts +10 -0
- package/src/notification/notification.module.ts +3 -0
- package/src/notification/notification.service.spec.ts +75 -1
- package/src/notification/notification.service.ts +39 -1
- package/src/oauth/oauth.controller.ts +0 -1
- package/src/oauth/oauth.errors.ts +7 -0
- package/src/oauth/oauth.module.ts +6 -1
- package/src/oauth/oauth.service.spec.ts +58 -7
- package/src/oauth/oauth.service.ts +71 -32
- package/src/oauth/providers/abstract.provider.spec.ts +192 -0
- package/src/oauth/providers/abstract.provider.ts +46 -14
- package/src/oauth/providers/github.provider.ts +57 -34
- package/src/oauth/providers/microsoft-entra-id.provider.ts +8 -1
- package/src/observability/monitored-cron.spec.ts +164 -31
- package/src/observability/monitored-cron.ts +154 -62
- package/src/profile/dto/change-password.dto.ts +25 -7
- package/src/profile/profile.service.spec.ts +97 -0
- package/src/profile/profile.service.ts +9 -3
- package/src/realtime/realtime-tick.coalescer.spec.ts +92 -0
- package/src/realtime/realtime-tick.coalescer.ts +60 -0
- package/src/realtime/realtime.service.spec.ts +33 -0
- package/src/realtime/realtime.service.ts +28 -2
- package/src/redis/redis-kv.service.ts +261 -0
- package/src/redis/redis-master.spec.ts +111 -0
- package/src/redis/redis-master.ts +86 -0
- package/src/redis/redis-pubsub.ts +27 -3
- package/src/redis/redis.module.ts +17 -0
- package/src/session/session.service.spec.ts +121 -42
- package/src/session/session.service.ts +279 -82
- package/src/setting/setting.service.ts +44 -3
- package/src/task/task.service.spec.ts +41 -0
- package/src/task/task.service.ts +53 -13
- package/src/token/token.service.spec.ts +90 -0
- package/src/token/token.service.ts +48 -2
- package/src/user/user-credential.util.ts +14 -5
- package/src/user/user.service.ts +2 -12
- package/src/user/user.sort.ts +25 -0
- package/src/utils/abbreviate-name.spec.ts +50 -0
- package/src/utils/abbreviate-name.ts +44 -0
- package/src/utils/date-range-query.dto.ts +56 -0
- package/src/utils/date-range.spec.ts +175 -0
- package/src/utils/date-range.ts +246 -0
- package/src/webhook-integration/webhook-utils.spec.ts +67 -0
- package/src/webhook-integration/webhook-utils.ts +26 -0
- package/src/whatsapp-sender/whatsapp-recipients.spec.ts +89 -0
- package/src/whatsapp-sender/whatsapp-recipients.ts +83 -0
- package/src/whatsapp-sender/whatsapp-sender.service.spec.ts +112 -0
- package/src/whatsapp-sender/whatsapp-sender.service.ts +58 -5
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { randomUUID } from 'node:crypto';
|
|
15
15
|
import { DeleteDTO } from '../dto/delete.dto';
|
|
16
16
|
import { createRedisPubSub, type RedisPubSub } from '../redis/redis-pubsub';
|
|
17
|
+
import { AI_INSTRUCTION_SORT } from './ai-instruction.sort';
|
|
17
18
|
import {
|
|
18
19
|
type AiPromptDefinition,
|
|
19
20
|
getAiPromptDefinition,
|
|
@@ -468,44 +469,47 @@ export class AiInstructionService implements OnModuleInit, OnModuleDestroy {
|
|
|
468
469
|
async list(paginationParams: PaginationDTO, filters?: AiInstructionListFilters) {
|
|
469
470
|
const page = Math.max(Number(paginationParams?.page || 1), 1);
|
|
470
471
|
const pageSize = Math.min(Math.max(Number(paginationParams?.pageSize || 20), 1), 100);
|
|
471
|
-
const
|
|
472
|
+
const skip = (page - 1) * pageSize;
|
|
472
473
|
const search = String(paginationParams?.search || '').trim();
|
|
473
474
|
|
|
474
|
-
const
|
|
475
|
+
const where: Prisma.ai_instructionWhereInput = {};
|
|
475
476
|
|
|
476
477
|
if (search) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
478
|
+
where.OR = [
|
|
479
|
+
{ slug: { contains: search, mode: 'insensitive' } },
|
|
480
|
+
{ name: { contains: search, mode: 'insensitive' } },
|
|
481
|
+
];
|
|
480
482
|
}
|
|
481
483
|
if (filters?.layer) {
|
|
482
|
-
|
|
484
|
+
where.layer = filters.layer;
|
|
483
485
|
}
|
|
484
486
|
if (filters?.module_slug) {
|
|
485
|
-
|
|
487
|
+
where.module_slug = filters.module_slug;
|
|
486
488
|
}
|
|
487
489
|
if (filters?.is_active !== undefined) {
|
|
488
|
-
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
`)
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
490
|
+
where.is_active = filters.is_active;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const [rows, total] = await Promise.all([
|
|
494
|
+
this.prisma.ai_instruction.findMany({
|
|
495
|
+
where,
|
|
496
|
+
orderBy: AI_INSTRUCTION_SORT.toPrismaOrderBy(paginationParams),
|
|
497
|
+
skip,
|
|
498
|
+
take: pageSize,
|
|
499
|
+
}),
|
|
500
|
+
this.prisma.ai_instruction.count({ where }),
|
|
501
|
+
]);
|
|
502
|
+
|
|
503
|
+
// `$queryRaw` cast `temperature::float8` explicitly (Decimal serializes as
|
|
504
|
+
// string otherwise and breaks `AiInstructionRecord.temperature: number`).
|
|
505
|
+
// `variables_schema` is `jsonb`; Prisma types it as the general `JsonValue`
|
|
506
|
+
// union, but this column only ever stores an object (or null) — same as
|
|
507
|
+
// the raw-SQL path, which returned it already parsed.
|
|
508
|
+
const data: AiInstructionRecord[] = rows.map((row) => ({
|
|
509
|
+
...row,
|
|
510
|
+
temperature: row.temperature === null ? null : Number(row.temperature),
|
|
511
|
+
variables_schema: row.variables_schema as Record<string, any> | null,
|
|
512
|
+
}));
|
|
509
513
|
|
|
510
514
|
return {
|
|
511
515
|
data,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineSortable } from '@hed-hog/api-pagination';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Campos ordenáveis de `ai_instruction` (`AiInstructionService.list`).
|
|
5
|
+
*
|
|
6
|
+
* `model`/`temperature`/`max_tokens` (coluna "Parâmetros" da tela, concatenados
|
|
7
|
+
* em `renderModelParams`) e o estado calculado a partir do registry + flags
|
|
8
|
+
* (coluna "Estado") ficam de fora: nenhum dos dois é uma coluna única — não há
|
|
9
|
+
* como declarar um `orderBy` que corresponda ao que a célula mostra.
|
|
10
|
+
*
|
|
11
|
+
* Desempate: o `$queryRaw` antigo tinha `ORDER BY layer, slug` fixo (as duas
|
|
12
|
+
* sempre ascendentes, sem opção de inverter). O default abaixo reproduz isso
|
|
13
|
+
* com `default: 'layer', defaultOrder: 'asc'` e `tiebreaker: 'slug'` fixado em
|
|
14
|
+
* `'asc'` (em vez do `id` padrão do `defineSortable`) — mais fiel ao
|
|
15
|
+
* comportamento anterior do que cair no id como desempate.
|
|
16
|
+
*/
|
|
17
|
+
export const AI_INSTRUCTION_SORT = defineSortable(
|
|
18
|
+
{
|
|
19
|
+
slug: true,
|
|
20
|
+
name: true,
|
|
21
|
+
layer: true,
|
|
22
|
+
module_slug: true,
|
|
23
|
+
version: true,
|
|
24
|
+
updated_at: { initialOrder: 'desc' },
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
default: 'layer',
|
|
28
|
+
defaultOrder: 'asc',
|
|
29
|
+
tiebreaker: 'slug',
|
|
30
|
+
tiebreakerOrder: 'asc',
|
|
31
|
+
},
|
|
32
|
+
);
|
package/src/auth/auth.module.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { JwtModule } from '@nestjs/jwt';
|
|
|
8
8
|
import cookieParser from 'cookie-parser';
|
|
9
9
|
import { ChallengeModule } from '../challenge/challenge.module';
|
|
10
10
|
import { ChallengeService } from '../challenge/challenge.service';
|
|
11
|
+
import { OAuthMetadataService } from '../authorize/oauth-metadata.service';
|
|
11
12
|
import { MailSentModule } from '../mail-sent/mail-sent.module';
|
|
12
13
|
import { MailModule } from '../mail/mail.module';
|
|
13
14
|
import { SecurityModule } from '../security/security.module';
|
|
@@ -88,12 +89,18 @@ import { AuthGuard } from './guards/auth.guard';
|
|
|
88
89
|
AuthService,
|
|
89
90
|
TokenService,
|
|
90
91
|
ChallengeService,
|
|
92
|
+
// Declarado aqui, e nao em AuthorizeModule (onde o arquivo mora), porque o
|
|
93
|
+
// AuthGuard abaixo e um APP_GUARD deste modulo: um provider de outro modulo
|
|
94
|
+
// so seria resolvido importando AuthorizeModule, que por sua vez importa
|
|
95
|
+
// AuthModule — circulo. Como este modulo e @Global, exportar aqui atende
|
|
96
|
+
// tambem o McpAuthGuard, sem ninguem precisar importar nada.
|
|
97
|
+
OAuthMetadataService,
|
|
91
98
|
{
|
|
92
99
|
provide: APP_GUARD,
|
|
93
100
|
useClass: AuthGuard,
|
|
94
101
|
},
|
|
95
102
|
],
|
|
96
|
-
exports: [AuthService],
|
|
103
|
+
exports: [AuthService, OAuthMetadataService],
|
|
97
104
|
})
|
|
98
105
|
export class AuthModule {
|
|
99
106
|
configure(consumer: MiddlewareConsumer) {
|
|
@@ -63,6 +63,7 @@ const makeDeps = () => {
|
|
|
63
63
|
setRefreshTokenCookie: jest.fn(),
|
|
64
64
|
};
|
|
65
65
|
const session = {
|
|
66
|
+
peekByRefreshToken: jest.fn<any>().mockResolvedValue({ id: 2, user_id: 9, audience: null, oauth_client_id: null, revoked_at: null, expires_at: new Date('2099-01-01') }),
|
|
66
67
|
create: jest.fn(),
|
|
67
68
|
refresh: jest.fn(),
|
|
68
69
|
deleteRefreshTokenCookie: jest.fn(),
|
|
@@ -120,7 +121,7 @@ describe('AuthService', () => {
|
|
|
120
121
|
|
|
121
122
|
const result = await service.getAuthenticationPayload('pt-BR', 1, '1.2.3.4', 'UA', 'browser-1');
|
|
122
123
|
|
|
123
|
-
expect(deps.session.create).toHaveBeenCalledWith('pt-BR', 1, '1.2.3.4', 'UA', 'browser-1');
|
|
124
|
+
expect(deps.session.create).toHaveBeenCalledWith('pt-BR', 1, '1.2.3.4', 'UA', 'browser-1', undefined);
|
|
124
125
|
expect(deps.prisma.user.update).toHaveBeenCalledWith({
|
|
125
126
|
where: { id: 1 },
|
|
126
127
|
data: { last_login_at: expect.any(Date) },
|
|
@@ -202,6 +203,37 @@ describe('AuthService', () => {
|
|
|
202
203
|
).rejects.toThrow(BadRequestException);
|
|
203
204
|
});
|
|
204
205
|
|
|
206
|
+
it('recusa a senha de credencial revogada', async () => {
|
|
207
|
+
// A revogação é o que o convite de acesso enterprise usa para trocar
|
|
208
|
+
// "autorize o acesso" por "crie sua conta e defina a senha"
|
|
209
|
+
// (`notifyAdminAccess` com `resetPassword`). Antes deste filtro, o login
|
|
210
|
+
// ignorava `revoked_at` e a senha antiga continuava entrando — enquanto o
|
|
211
|
+
// "esqueci minha senha", que sempre exigiu credencial ativa, dizia que a
|
|
212
|
+
// conta não tinha senha.
|
|
213
|
+
const { service, deps } = makeService();
|
|
214
|
+
deps.user.findUserByEmail.mockResolvedValue({
|
|
215
|
+
id: 1,
|
|
216
|
+
user_credential: [{ type: 'password', revoked_at: new Date() }],
|
|
217
|
+
user_identifier: [{ type: 'email', value: 'a@b.com' }],
|
|
218
|
+
});
|
|
219
|
+
deps.security.validatePassword.mockResolvedValue(false);
|
|
220
|
+
|
|
221
|
+
await expect(
|
|
222
|
+
service.loginWithEmailAndPassword({}, 'pt-BR', '1.1.1.1', 'UA', {
|
|
223
|
+
email: 'a@b.com',
|
|
224
|
+
password: 'a-senha-revogada',
|
|
225
|
+
} as any),
|
|
226
|
+
).rejects.toThrow(BadRequestException);
|
|
227
|
+
|
|
228
|
+
// Sem credencial ativa não há o que verificar: a lista chega vazia, e é isso
|
|
229
|
+
// que garante que nenhum hash revogado é comparado.
|
|
230
|
+
expect(deps.security.validatePassword).toHaveBeenCalledWith(
|
|
231
|
+
'pt-BR',
|
|
232
|
+
[],
|
|
233
|
+
'a-senha-revogada',
|
|
234
|
+
);
|
|
235
|
+
});
|
|
236
|
+
|
|
205
237
|
it('retorna requiresMfa quando existem métodos MFA verificados, enviando código para emails MFA', async () => {
|
|
206
238
|
const { service, deps } = makeService();
|
|
207
239
|
deps.user.findUserByEmail.mockResolvedValue({
|
|
@@ -680,6 +712,81 @@ describe('AuthService', () => {
|
|
|
680
712
|
session: { id: 2, user_id: 9 },
|
|
681
713
|
});
|
|
682
714
|
});
|
|
715
|
+
|
|
716
|
+
// Sem esta recusa, um cliente externo trocaria o refresh token restrito por
|
|
717
|
+
// uma sessao com acesso a API inteira, e o audience binding nao valeria nada.
|
|
718
|
+
it('recusa renovar uma sessao de conector (com audience)', async () => {
|
|
719
|
+
const { service, deps } = makeService();
|
|
720
|
+
deps.session.peekByRefreshToken.mockResolvedValue({
|
|
721
|
+
id: 2,
|
|
722
|
+
user_id: 9,
|
|
723
|
+
audience: 'https://hub-api.example.com/mcp',
|
|
724
|
+
oauth_client_id: 'claude-connector',
|
|
725
|
+
revoked_at: null,
|
|
726
|
+
expires_at: new Date('2099-01-01'),
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
await expect(
|
|
730
|
+
service.refreshAccessToken('pt-BR', 'connector-refresh', '1.1.1.1', 'UA'),
|
|
731
|
+
).rejects.toThrow(UnauthorizedException);
|
|
732
|
+
|
|
733
|
+
expect(deps.token.createAccessToken).not.toHaveBeenCalled();
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* REGRESSAO: a recusa acontecia DEPOIS de session.refresh(), que ja commitou
|
|
738
|
+
* o compare-and-swap — o cliente ficava com um token morto em 30s e sem
|
|
739
|
+
* substituto. Negar um pedido nao pode destruir a sessao.
|
|
740
|
+
*/
|
|
741
|
+
it('nao gira o refresh token quando vai recusar', async () => {
|
|
742
|
+
const { service, deps } = makeService();
|
|
743
|
+
deps.session.peekByRefreshToken.mockResolvedValue({
|
|
744
|
+
id: 2,
|
|
745
|
+
user_id: 9,
|
|
746
|
+
audience: 'https://hub-api.example.com/mcp',
|
|
747
|
+
oauth_client_id: 'claude-connector',
|
|
748
|
+
revoked_at: null,
|
|
749
|
+
expires_at: new Date('2099-01-01'),
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
await expect(
|
|
753
|
+
service.refreshAccessToken('pt-BR', 'connector-refresh', '1.1.1.1', 'UA'),
|
|
754
|
+
).rejects.toThrow(UnauthorizedException);
|
|
755
|
+
|
|
756
|
+
expect(deps.session.refresh).not.toHaveBeenCalled();
|
|
757
|
+
});
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
describe('getAuthenticationPayload - fluxo OAuth com resource', () => {
|
|
761
|
+
it('emite aud, iss, scope e cid e marca a sessao', async () => {
|
|
762
|
+
const { service, deps } = makeService();
|
|
763
|
+
deps.session.create.mockResolvedValue({
|
|
764
|
+
token: 'refresh-token',
|
|
765
|
+
session: { id: 5, expires_at: new Date('2026-01-02') },
|
|
766
|
+
});
|
|
767
|
+
deps.token.createAccessToken.mockResolvedValue('access-token');
|
|
768
|
+
|
|
769
|
+
await service.getAuthenticationPayload('pt-BR', 1, '1.2.3.4', 'UA', null, {
|
|
770
|
+
audience: 'https://hub-api.example.com/mcp',
|
|
771
|
+
scope: 'mcp',
|
|
772
|
+
clientId: 'claude-connector',
|
|
773
|
+
issuer: 'https://hub-api.example.com',
|
|
774
|
+
ttlMinutes: 10080,
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
expect(deps.token.createAccessToken).toHaveBeenCalledWith({
|
|
778
|
+
sub: 1,
|
|
779
|
+
sessionId: 5,
|
|
780
|
+
aud: 'https://hub-api.example.com/mcp',
|
|
781
|
+
iss: 'https://hub-api.example.com',
|
|
782
|
+
scope: 'mcp',
|
|
783
|
+
cid: 'claude-connector',
|
|
784
|
+
});
|
|
785
|
+
expect(deps.session.create).toHaveBeenCalledWith(
|
|
786
|
+
'pt-BR', 1, '1.2.3.4', 'UA', null,
|
|
787
|
+
{ audience: 'https://hub-api.example.com/mcp', clientId: 'claude-connector', ttlMinutes: 10080 },
|
|
788
|
+
);
|
|
789
|
+
});
|
|
683
790
|
});
|
|
684
791
|
|
|
685
792
|
describe('forgotPassword / logout', () => {
|
package/src/auth/auth.service.ts
CHANGED
|
@@ -24,7 +24,7 @@ import { SessionService } from '../session/session.service';
|
|
|
24
24
|
import { SettingService } from '../setting/setting.service';
|
|
25
25
|
import { TokenService } from '../token/token.service';
|
|
26
26
|
import { UserDeviceService } from '../user-device/user-device.service';
|
|
27
|
-
import { hasPendingPasswordReset } from '../user/user-credential.util';
|
|
27
|
+
import { hasPendingPasswordReset, isActivePasswordCredential } from '../user/user-credential.util';
|
|
28
28
|
import { CreateWithEmailAndPasswordDTO } from '../user/dto/create-with-email-and-password.dto';
|
|
29
29
|
import { UserService } from '../user/user.service';
|
|
30
30
|
import { buildSecurityEventVars } from '../utils/security-event-vars';
|
|
@@ -57,9 +57,40 @@ export class AuthService {
|
|
|
57
57
|
private readonly userDevice: UserDeviceService,
|
|
58
58
|
) { }
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
/**
|
|
61
|
+
* `oauth` so vem preenchido quando a troca do authorization code pediu um
|
|
62
|
+
* `resource` (RFC 8707). Nesse caso o access token nasce amarrado aquele
|
|
63
|
+
* recurso — e o TokenService passa a recusa-lo em qualquer outro lugar. Sem o
|
|
64
|
+
* parametro, o token e o de sempre: sem `aud`, valido na API inteira.
|
|
65
|
+
*/
|
|
66
|
+
async getAuthenticationPayload(
|
|
67
|
+
locale: string,
|
|
68
|
+
userId: number,
|
|
69
|
+
ipAddress: string,
|
|
70
|
+
userAgent: string,
|
|
71
|
+
browserId?: string | null,
|
|
72
|
+
oauth?: { audience: string; scope: string; clientId: string; issuer: string; ttlMinutes?: number },
|
|
73
|
+
) {
|
|
74
|
+
const { token: refreshToken, session } = await this.session.create(
|
|
75
|
+
locale,
|
|
76
|
+
userId,
|
|
77
|
+
ipAddress,
|
|
78
|
+
userAgent,
|
|
79
|
+
browserId,
|
|
80
|
+
oauth
|
|
81
|
+
? { audience: oauth.audience, clientId: oauth.clientId, ttlMinutes: oauth.ttlMinutes }
|
|
82
|
+
: undefined,
|
|
83
|
+
);
|
|
84
|
+
const payload = oauth
|
|
85
|
+
? {
|
|
86
|
+
sub: userId,
|
|
87
|
+
sessionId: session.id,
|
|
88
|
+
aud: oauth.audience,
|
|
89
|
+
iss: oauth.issuer,
|
|
90
|
+
scope: oauth.scope,
|
|
91
|
+
cid: oauth.clientId,
|
|
92
|
+
}
|
|
93
|
+
: { sub: userId, sessionId: session.id };
|
|
63
94
|
const accessToken = await this.token.createAccessToken(payload);
|
|
64
95
|
await this.prisma.user.update({ where: { id: userId }, data: { last_login_at: new Date() } });
|
|
65
96
|
|
|
@@ -525,7 +556,11 @@ export class AuthService {
|
|
|
525
556
|
|
|
526
557
|
if (!user) throw new BadRequestException(getLocaleText('accessDenied', locale, 'Access denied.'));
|
|
527
558
|
|
|
528
|
-
|
|
559
|
+
// Revogada não vale: sem o `revoked_at` aqui, revogar a senha (o que o convite
|
|
560
|
+
// de acesso enterprise faz para forçar a definição de uma nova) não impedia o
|
|
561
|
+
// login com a senha antiga. Mesmo critério de `hasPasswordCredential`, que é
|
|
562
|
+
// o que decide se o "esqueci minha senha" pode seguir.
|
|
563
|
+
const credentials = (user as unknown as User).user_credential?.filter(isActivePasswordCredential) || [];
|
|
529
564
|
|
|
530
565
|
const identifier = user.user_identifier?.find((i) => i.type === 'email' && i.value === email);
|
|
531
566
|
|
|
@@ -692,6 +727,13 @@ export class AuthService {
|
|
|
692
727
|
};
|
|
693
728
|
}
|
|
694
729
|
|
|
730
|
+
/**
|
|
731
|
+
* POST /auth/refresh e publico e devolve um token SEM `aud`. Se aceitasse o
|
|
732
|
+
* refresh token de um conector, o cliente externo trocaria seu token restrito
|
|
733
|
+
* por uma sessao com acesso a API inteira e todo o audience binding viraria
|
|
734
|
+
* enfeite. A renovacao dele e o grant_type=refresh_token do /auth/token, que
|
|
735
|
+
* reaplica o `aud`.
|
|
736
|
+
*/
|
|
695
737
|
async refreshAccessToken(locale: string, refreshToken: string, ipAddress: string, userAgent: string, browserId?: string | null) {
|
|
696
738
|
|
|
697
739
|
if (!refreshToken) {
|
|
@@ -701,6 +743,18 @@ export class AuthService {
|
|
|
701
743
|
|
|
702
744
|
this.logger.debug(`[AuthService] refreshAccessToken ip=${ipAddress} ua=${userAgent?.slice(0, 40)}`);
|
|
703
745
|
|
|
746
|
+
// ANTES de girar. `session.refresh()` commita a rotacao assim que roda, com
|
|
747
|
+
// apenas 30s de graca para o token anterior — recusar depois dela deixaria o
|
|
748
|
+
// cliente sem o token novo e com o antigo prestes a morrer, ou seja,
|
|
749
|
+
// destruiria a sessao em vez de negar o pedido.
|
|
750
|
+
const existing = await this.session.peekByRefreshToken(refreshToken);
|
|
751
|
+
if (existing?.audience) {
|
|
752
|
+
this.logger.warn(
|
|
753
|
+
`[AuthService] refreshAccessToken rejected: sessionId=${existing.id} userId=${existing.user_id} belongs to resource ${existing.audience}`,
|
|
754
|
+
);
|
|
755
|
+
throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
|
|
756
|
+
}
|
|
757
|
+
|
|
704
758
|
const { session, token } = await this.session.refresh(
|
|
705
759
|
locale,
|
|
706
760
|
refreshToken,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { Reflector } from '@nestjs/core';
|
|
12
12
|
import { Request } from 'express';
|
|
13
13
|
import { ALLOW_MCP_TOKEN } from '../../mcp/decorators/allow-mcp-token.decorator';
|
|
14
|
+
import { OAuthMetadataService } from '../../authorize/oauth-metadata.service';
|
|
14
15
|
import { SecurityService } from '../../security/security.service';
|
|
15
16
|
import { TokenService } from '../../token/token.service';
|
|
16
17
|
|
|
@@ -23,6 +24,7 @@ export class AuthGuard implements CanActivate {
|
|
|
23
24
|
private reflector: Reflector,
|
|
24
25
|
private prisma: PrismaService,
|
|
25
26
|
private security: SecurityService,
|
|
27
|
+
private oauthMetadata: OAuthMetadataService,
|
|
26
28
|
) { }
|
|
27
29
|
|
|
28
30
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
@@ -89,7 +91,13 @@ export class AuthGuard implements CanActivate {
|
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
try {
|
|
92
|
-
|
|
94
|
+
// So o /mcp e um "recurso" com audiencia propria. Em todo o resto o terceiro
|
|
95
|
+
// argumento fica ausente de proposito: e a ausencia que faz um token de
|
|
96
|
+
// conector ser recusado no REST.
|
|
97
|
+
const allowedAudience = allowMcpToken
|
|
98
|
+
? await this.oauthMetadata.getMcpResource()
|
|
99
|
+
: undefined;
|
|
100
|
+
const payload = await this.token.verify(locale, token, allowedAudience);
|
|
93
101
|
|
|
94
102
|
request['auth'] = payload;
|
|
95
103
|
} catch (error) {
|
|
@@ -4,16 +4,23 @@ import {
|
|
|
4
4
|
Body,
|
|
5
5
|
Controller,
|
|
6
6
|
Get,
|
|
7
|
+
Header,
|
|
7
8
|
Headers,
|
|
8
9
|
Inject,
|
|
9
10
|
Ip,
|
|
10
11
|
Post,
|
|
11
12
|
Query,
|
|
13
|
+
Res,
|
|
14
|
+
UseFilters,
|
|
12
15
|
UseGuards,
|
|
13
16
|
forwardRef,
|
|
14
17
|
} from '@nestjs/common';
|
|
15
18
|
import { Throttle, ThrottlerGuard } from '@nestjs/throttler';
|
|
19
|
+
import type { Response } from 'express';
|
|
20
|
+
import { OAuthError } from './authorize.errors';
|
|
16
21
|
import { AuthorizeService } from './authorize.service';
|
|
22
|
+
import { OAuthMetadataService } from './oauth-metadata.service';
|
|
23
|
+
import { OAuthExceptionFilter } from './oauth-exception.filter';
|
|
17
24
|
import { AuthorizeInfoDTO } from './dto/authorize-info.dto';
|
|
18
25
|
import { ConsentDTO } from './dto/consent.dto';
|
|
19
26
|
import { TokenDTO } from './dto/token.dto';
|
|
@@ -21,18 +28,87 @@ import { TokenDTO } from './dto/token.dto';
|
|
|
21
28
|
/**
|
|
22
29
|
* Endpoints do fluxo Authorization Code + PKCE.
|
|
23
30
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* POST /auth/authorize/consent
|
|
27
|
-
* `code`
|
|
31
|
+
* O `GET /auth/authorize` daqui NÃO emite o `code`: ele valida e redireciona para
|
|
32
|
+
* a tela de consent do admin, que é quem faz o redirect final depois do
|
|
33
|
+
* `POST /auth/authorize/consent`. A restrição original continua valendo — o
|
|
34
|
+
* `code` nunca passa pelo mecanismo de redirect do Nest, nem pelos seus logs.
|
|
35
|
+
*
|
|
36
|
+
* Ele existe porque um cliente OAuth padrão (o conector do Claude) espera um
|
|
37
|
+
* `authorization_endpoint` na mesma origem do `issuer`, e porque a validação de
|
|
38
|
+
* `response_type`, `scope` e `resource` tem que acontecer no servidor, antes de
|
|
39
|
+
* qualquer render — um erro precisa voltar como `error=` na query, e não como uma
|
|
40
|
+
* tela morta.
|
|
28
41
|
*/
|
|
29
42
|
@Controller('auth')
|
|
30
43
|
export class AuthorizeController {
|
|
31
44
|
constructor(
|
|
32
45
|
@Inject(forwardRef(() => AuthorizeService))
|
|
33
46
|
private readonly service: AuthorizeService,
|
|
47
|
+
@Inject(forwardRef(() => OAuthMetadataService))
|
|
48
|
+
private readonly metadata: OAuthMetadataService,
|
|
34
49
|
) {}
|
|
35
50
|
|
|
51
|
+
/**
|
|
52
|
+
* O authorization endpoint anunciado nos metadados.
|
|
53
|
+
*
|
|
54
|
+
* A ordem de validação é normativa (RFC 6749 §4.1.2.1): `client_id` e
|
|
55
|
+
* `redirect_uri` primeiro, e falha neles NÃO redireciona — sem um redirect_uri
|
|
56
|
+
* validado, redirecionar seria mandar o usuário para onde o atacante pediu.
|
|
57
|
+
* Tudo o mais volta para o cliente como `error` na query.
|
|
58
|
+
*/
|
|
59
|
+
@Public()
|
|
60
|
+
@UseGuards(ThrottlerGuard)
|
|
61
|
+
@Throttle({ default: { limit: 30, ttl: 60000 } })
|
|
62
|
+
@UseFilters(OAuthExceptionFilter)
|
|
63
|
+
@Get('authorize')
|
|
64
|
+
async authorize(@Query() query: AuthorizeInfoDTO, @Res() res: Response) {
|
|
65
|
+
try {
|
|
66
|
+
await this.service.getAuthorizationInfo({
|
|
67
|
+
clientId: query.client_id,
|
|
68
|
+
redirectUri: query.redirect_uri,
|
|
69
|
+
scope: query.scope,
|
|
70
|
+
codeChallenge: query.code_challenge,
|
|
71
|
+
codeChallengeMethod: query.code_challenge_method,
|
|
72
|
+
responseType: query.response_type,
|
|
73
|
+
resource: query.resource,
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
if (error instanceof OAuthError && error.redirectable) {
|
|
77
|
+
return res.redirect(
|
|
78
|
+
302,
|
|
79
|
+
await this.buildErrorRedirect(query, error),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Só parâmetros validados seguem para a tela. O `code` é emitido lá, pelo
|
|
86
|
+
// consent, e volta por um redirect do browser — não por este.
|
|
87
|
+
const consentBase = await this.metadata.getConsentUiBase();
|
|
88
|
+
const params = new URLSearchParams();
|
|
89
|
+
for (const [key, value] of Object.entries(query)) {
|
|
90
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
91
|
+
params.set(key, String(value));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return res.redirect(302, `${consentBase}/auth/authorize?${params.toString()}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private async buildErrorRedirect(
|
|
99
|
+
query: AuthorizeInfoDTO,
|
|
100
|
+
error: OAuthError,
|
|
101
|
+
): Promise<string> {
|
|
102
|
+
const target = new URL(query.redirect_uri);
|
|
103
|
+
target.searchParams.set('error', error.code);
|
|
104
|
+
target.searchParams.set('error_description', error.description);
|
|
105
|
+
if (query.state) target.searchParams.set('state', query.state);
|
|
106
|
+
// RFC 9207: vai também no erro, e o cliente valida antes de exibir qualquer
|
|
107
|
+
// coisa. Anunciamos `authorization_response_iss_parameter_supported`.
|
|
108
|
+
target.searchParams.set('iss', await this.metadata.getIssuer());
|
|
109
|
+
return target.toString();
|
|
110
|
+
}
|
|
111
|
+
|
|
36
112
|
/**
|
|
37
113
|
* Metadados para a tela de consent. Público: a página precisa validar os
|
|
38
114
|
* parâmetros e mostrar de quem é o app ANTES de exigir login.
|
|
@@ -42,13 +118,32 @@ export class AuthorizeController {
|
|
|
42
118
|
@Throttle({ default: { limit: 30, ttl: 60000 } })
|
|
43
119
|
@Get('authorize/info')
|
|
44
120
|
async authorizeInfo(@Query() query: AuthorizeInfoDTO) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
121
|
+
try {
|
|
122
|
+
return await this.service.getAuthorizationInfo({
|
|
123
|
+
clientId: query.client_id,
|
|
124
|
+
redirectUri: query.redirect_uri,
|
|
125
|
+
scope: query.scope,
|
|
126
|
+
codeChallenge: query.code_challenge,
|
|
127
|
+
codeChallengeMethod: query.code_challenge_method,
|
|
128
|
+
responseType: query.response_type,
|
|
129
|
+
resource: query.resource,
|
|
130
|
+
});
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// Erro redirecionável volta para o cliente pelas mãos da tela, e o RFC 9207
|
|
133
|
+
// exige `iss` também nele. Mas a tela só aprende o issuer no caminho de
|
|
134
|
+
// SUCESSO desta chamada — num erro ela redirecionaria sem o parâmetro, e um
|
|
135
|
+
// cliente que o valide (nós anunciamos suportá-lo) rejeita a resposta
|
|
136
|
+
// inteira. Então o issuer viaja junto do erro.
|
|
137
|
+
if (error instanceof OAuthError && error.redirectable) {
|
|
138
|
+
throw new OAuthError(
|
|
139
|
+
error.code,
|
|
140
|
+
error.description,
|
|
141
|
+
true,
|
|
142
|
+
await this.metadata.getIssuer(),
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
52
147
|
}
|
|
53
148
|
|
|
54
149
|
/** O usuário logado aprova. O code sai vinculado a ele. */
|
|
@@ -64,6 +159,8 @@ export class AuthorizeController {
|
|
|
64
159
|
scope: body.scope,
|
|
65
160
|
codeChallenge: body.code_challenge,
|
|
66
161
|
codeChallengeMethod: body.code_challenge_method,
|
|
162
|
+
responseType: body.response_type,
|
|
163
|
+
resource: body.resource,
|
|
67
164
|
});
|
|
68
165
|
|
|
69
166
|
return { code };
|
|
@@ -79,6 +176,11 @@ export class AuthorizeController {
|
|
|
79
176
|
@Public()
|
|
80
177
|
@UseGuards(ThrottlerGuard)
|
|
81
178
|
@Throttle({ default: { limit: 20, ttl: 60000 } })
|
|
179
|
+
@UseFilters(OAuthExceptionFilter)
|
|
180
|
+
// RFC 6749 5.1: a resposta carrega credenciais e nao pode ser cacheada. O
|
|
181
|
+
// filtro ja poe isto nos erros; aqui vale para o sucesso.
|
|
182
|
+
@Header('Cache-Control', 'no-store')
|
|
183
|
+
@Header('Pragma', 'no-cache')
|
|
82
184
|
@Post('token')
|
|
83
185
|
async token(
|
|
84
186
|
@Body() body: TokenDTO,
|
|
@@ -87,11 +189,24 @@ export class AuthorizeController {
|
|
|
87
189
|
@Headers('user-agent') userAgent: string,
|
|
88
190
|
@Headers('x-browser-id') browserId: string,
|
|
89
191
|
) {
|
|
192
|
+
if (body.grant_type === 'refresh_token') {
|
|
193
|
+
return this.service.exchangeRefreshToken({
|
|
194
|
+
refreshToken: body.refresh_token,
|
|
195
|
+
clientId: body.client_id,
|
|
196
|
+
resource: body.resource,
|
|
197
|
+
locale,
|
|
198
|
+
ipAddress,
|
|
199
|
+
userAgent,
|
|
200
|
+
browserId: browserId || null,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
90
204
|
return this.service.exchangeCode({
|
|
91
205
|
code: body.code,
|
|
92
206
|
codeVerifier: body.code_verifier,
|
|
93
207
|
clientId: body.client_id,
|
|
94
208
|
redirectUri: body.redirect_uri,
|
|
209
|
+
resource: body.resource,
|
|
95
210
|
locale,
|
|
96
211
|
ipAddress,
|
|
97
212
|
userAgent,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { BadRequestException } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Códigos de erro do RFC 6749 §4.1.2.1 e §5.2, mais o `invalid_target` do
|
|
5
|
+
* RFC 8707.
|
|
6
|
+
*/
|
|
7
|
+
export type OAuthErrorCode =
|
|
8
|
+
| 'invalid_request'
|
|
9
|
+
| 'invalid_client'
|
|
10
|
+
| 'invalid_grant'
|
|
11
|
+
| 'unauthorized_client'
|
|
12
|
+
| 'unsupported_grant_type'
|
|
13
|
+
| 'unsupported_response_type'
|
|
14
|
+
| 'invalid_scope'
|
|
15
|
+
| 'invalid_target'
|
|
16
|
+
| 'access_denied'
|
|
17
|
+
| 'login_required'
|
|
18
|
+
| 'server_error';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Erro do fluxo OAuth.
|
|
22
|
+
*
|
|
23
|
+
* `redirectable` decide o que acontece com ele, e a distinção é normativa
|
|
24
|
+
* (RFC 6749 §4.1.2.1): erro de `client_id` ou de `redirect_uri` **não** pode
|
|
25
|
+
* voltar para o `redirect_uri` — se ele não foi validado, redirecionar seria
|
|
26
|
+
* mandar o usuário para onde o atacante pediu. Todo o resto volta para o cliente
|
|
27
|
+
* como `error` na query, que é como ele descobre o que fez de errado.
|
|
28
|
+
*/
|
|
29
|
+
export class OAuthError extends BadRequestException {
|
|
30
|
+
// Herda de BadRequestException, e nao de HttpException direto: todo erro OAuth
|
|
31
|
+
// de requisicao e um 400, e manter a hierarquia preserva qualquer `catch` que
|
|
32
|
+
// ja exista para BadRequestException — inclusive os testes que descrevem o
|
|
33
|
+
// comportamento anterior.
|
|
34
|
+
constructor(
|
|
35
|
+
readonly code: OAuthErrorCode,
|
|
36
|
+
readonly description: string,
|
|
37
|
+
readonly redirectable = false,
|
|
38
|
+
/**
|
|
39
|
+
* Só acompanha erro redirecionável: é o `iss` que a tela precisa devolver ao
|
|
40
|
+
* cliente junto do erro (RFC 9207). No caminho de sucesso ela já o recebe em
|
|
41
|
+
* `getAuthorizationInfo`.
|
|
42
|
+
*/
|
|
43
|
+
readonly issuer?: string,
|
|
44
|
+
) {
|
|
45
|
+
super({
|
|
46
|
+
error: code,
|
|
47
|
+
error_description: description,
|
|
48
|
+
redirectable,
|
|
49
|
+
...(issuer ? { issuer } : {}),
|
|
50
|
+
// `message` fica junto porque os clientes ja registrados leem esse campo
|
|
51
|
+
// nas respostas de erro de hoje. Tirar seria uma quebra silenciosa.
|
|
52
|
+
message: description,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|