@hed-hog/core 0.0.387 → 0.0.390
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/README.md +12 -11
- package/dist/access-log/access-log.interceptor.d.ts.map +1 -1
- package/dist/access-log/access-log.interceptor.js +4 -2
- package/dist/access-log/access-log.interceptor.js.map +1 -1
- package/dist/ai/ai-attachment.fragments.d.ts +23 -0
- package/dist/ai/ai-attachment.fragments.d.ts.map +1 -0
- package/dist/ai/ai-attachment.fragments.js +34 -0
- package/dist/ai/ai-attachment.fragments.js.map +1 -0
- package/dist/ai/ai.controller.d.ts +7 -16
- package/dist/ai/ai.controller.d.ts.map +1 -1
- package/dist/ai/ai.prompts.d.ts +16 -0
- package/dist/ai/ai.prompts.d.ts.map +1 -0
- package/dist/ai/ai.prompts.js +37 -0
- package/dist/ai/ai.prompts.js.map +1 -0
- package/dist/ai/ai.service.d.ts +63 -12
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +215 -88
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/ai/dto/chat.dto.d.ts +4 -1
- package/dist/ai/dto/chat.dto.d.ts.map +1 -1
- package/dist/ai/dto/chat.dto.js +23 -1
- package/dist/ai/dto/chat.dto.js.map +1 -1
- package/dist/ai/dto/create-agent.dto.d.ts +1 -1
- package/dist/ai/dto/create-agent.dto.d.ts.map +1 -1
- package/dist/ai/dto/create-agent.dto.js +1 -1
- package/dist/ai/dto/create-agent.dto.js.map +1 -1
- package/dist/ai/dto/update-agent.dto.d.ts +1 -1
- package/dist/ai/dto/update-agent.dto.d.ts.map +1 -1
- package/dist/ai/dto/update-agent.dto.js +1 -1
- package/dist/ai/dto/update-agent.dto.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.controller.d.ts +61 -7
- package/dist/ai-instruction/ai-instruction.controller.d.ts.map +1 -1
- package/dist/ai-instruction/ai-instruction.controller.js +63 -20
- package/dist/ai-instruction/ai-instruction.controller.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.module.d.ts.map +1 -1
- package/dist/ai-instruction/ai-instruction.module.js +13 -2
- package/dist/ai-instruction/ai-instruction.module.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.service.d.ts +131 -6
- package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -1
- package/dist/ai-instruction/ai-instruction.service.js +533 -60
- package/dist/ai-instruction/ai-instruction.service.js.map +1 -1
- package/dist/ai-instruction/ai-prompt-builder.service.d.ts +8 -0
- package/dist/ai-instruction/ai-prompt-builder.service.d.ts.map +1 -1
- package/dist/ai-instruction/ai-prompt-builder.service.js +10 -1
- package/dist/ai-instruction/ai-prompt-builder.service.js.map +1 -1
- package/dist/ai-instruction/ai-prompt-registry.d.ts +45 -0
- package/dist/ai-instruction/ai-prompt-registry.d.ts.map +1 -0
- package/dist/ai-instruction/ai-prompt-registry.js +49 -0
- package/dist/ai-instruction/ai-prompt-registry.js.map +1 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.d.ts +89 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.d.ts.map +1 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.js +222 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.js.map +1 -0
- package/dist/ai-instruction/ai-prompt-template.util.d.ts +70 -0
- package/dist/ai-instruction/ai-prompt-template.util.d.ts.map +1 -0
- package/dist/ai-instruction/ai-prompt-template.util.js +154 -0
- package/dist/ai-instruction/ai-prompt-template.util.js.map +1 -0
- package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts +5 -0
- package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts.map +1 -1
- package/dist/ai-instruction/dto/create-ai-instruction.dto.js +27 -1
- package/dist/ai-instruction/dto/create-ai-instruction.dto.js.map +1 -1
- package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts +14 -0
- package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts.map +1 -0
- package/dist/ai-instruction/dto/preview-ai-instruction.dto.js +42 -0
- package/dist/ai-instruction/dto/preview-ai-instruction.dto.js.map +1 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts +11 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts.map +1 -1
- package/dist/ai-instruction/dto/update-ai-instruction.dto.js +34 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.js.map +1 -1
- package/dist/ai-instruction/types/ai-instruction.types.d.ts +13 -1
- package/dist/ai-instruction/types/ai-instruction.types.d.ts.map +1 -1
- package/dist/ai-instruction/types/ai-instruction.types.js +10 -0
- package/dist/ai-instruction/types/ai-instruction.types.js.map +1 -1
- package/dist/auth/auth.controller.d.ts +24 -9
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +49 -21
- package/dist/auth/auth.controller.js.map +1 -1
- package/dist/auth/auth.service.d.ts +33 -8
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +78 -29
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/captcha/captcha.module.d.ts +3 -0
- package/dist/captcha/captcha.module.d.ts.map +1 -0
- package/dist/captcha/captcha.module.js +23 -0
- package/dist/captcha/captcha.module.js.map +1 -0
- package/dist/captcha/captcha.service.d.ts +38 -0
- package/dist/captcha/captcha.service.d.ts.map +1 -0
- package/dist/captcha/captcha.service.js +144 -0
- package/dist/captcha/captcha.service.js.map +1 -0
- package/dist/challenge/challenge.service.d.ts +16 -7
- package/dist/challenge/challenge.service.d.ts.map +1 -1
- package/dist/challenge/challenge.service.js +64 -16
- package/dist/challenge/challenge.service.js.map +1 -1
- package/dist/core.module.d.ts +3 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +29 -2
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard/dashboard.controller.d.ts +15 -15
- package/dist/dashboard/dashboard/dashboard.service.d.ts +15 -15
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +6 -6
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +6 -6
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +20 -20
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +20 -20
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +13 -13
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +13 -13
- package/dist/file/file.service.d.ts +6 -0
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +44 -4
- package/dist/file/file.service.js.map +1 -1
- package/dist/incident/incident-notifier.service.d.ts +36 -0
- package/dist/incident/incident-notifier.service.d.ts.map +1 -0
- package/dist/incident/incident-notifier.service.js +208 -0
- package/dist/incident/incident-notifier.service.js.map +1 -0
- package/dist/incident/incident.controller.d.ts +23 -0
- package/dist/incident/incident.controller.d.ts.map +1 -0
- package/dist/incident/incident.controller.js +75 -0
- package/dist/incident/incident.controller.js.map +1 -0
- package/dist/incident/incident.module.d.ts +7 -0
- package/dist/incident/incident.module.d.ts.map +1 -0
- package/dist/incident/incident.module.js +32 -0
- package/dist/incident/incident.module.js.map +1 -0
- package/dist/incident/incident.service.d.ts +72 -0
- package/dist/incident/incident.service.d.ts.map +1 -0
- package/dist/incident/incident.service.js +184 -0
- package/dist/incident/incident.service.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/dist/integration-profile/dto/test.dto.d.ts +13 -0
- package/dist/integration-profile/dto/test.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/test.dto.js +26 -0
- package/dist/integration-profile/dto/test.dto.js.map +1 -0
- package/dist/integration-profile/integration-profile.controller.d.ts +12 -1
- package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.controller.js +9 -1
- package/dist/integration-profile/integration-profile.controller.js.map +1 -1
- package/dist/integration-profile/integration-profile.module.d.ts +6 -1
- package/dist/integration-profile/integration-profile.module.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.module.js +26 -3
- package/dist/integration-profile/integration-profile.module.js.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.js +9 -1
- package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
- package/dist/integration-profile/integration-profile.service.d.ts +26 -7
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.service.js +94 -91
- package/dist/integration-profile/integration-profile.service.js.map +1 -1
- package/dist/integration-profile/integration-profile.utils.d.ts +13 -1
- package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.utils.js +20 -5
- package/dist/integration-profile/integration-profile.utils.js.map +1 -1
- package/dist/integration-profile/testers/ai.testers.d.ts +3 -0
- package/dist/integration-profile/testers/ai.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/ai.testers.js +125 -0
- package/dist/integration-profile/testers/ai.testers.js.map +1 -0
- package/dist/integration-profile/testers/captcha.testers.d.ts +3 -0
- package/dist/integration-profile/testers/captcha.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/captcha.testers.js +121 -0
- package/dist/integration-profile/testers/captcha.testers.js.map +1 -0
- package/dist/integration-profile/testers/email.testers.d.ts +3 -0
- package/dist/integration-profile/testers/email.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/email.testers.js +128 -0
- package/dist/integration-profile/testers/email.testers.js.map +1 -0
- package/dist/integration-profile/testers/http-probe.d.ts +57 -0
- package/dist/integration-profile/testers/http-probe.d.ts.map +1 -0
- package/dist/integration-profile/testers/http-probe.js +140 -0
- package/dist/integration-profile/testers/http-probe.js.map +1 -0
- package/dist/integration-profile/testers/index.d.ts +12 -0
- package/dist/integration-profile/testers/index.d.ts.map +1 -0
- package/dist/integration-profile/testers/index.js +45 -0
- package/dist/integration-profile/testers/index.js.map +1 -0
- package/dist/integration-profile/testers/infrastructure.testers.d.ts +3 -0
- package/dist/integration-profile/testers/infrastructure.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/infrastructure.testers.js +105 -0
- package/dist/integration-profile/testers/infrastructure.testers.js.map +1 -0
- package/dist/integration-profile/testers/integration-tester.registry.d.ts +17 -0
- package/dist/integration-profile/testers/integration-tester.registry.d.ts.map +1 -0
- package/dist/integration-profile/testers/integration-tester.registry.js +52 -0
- package/dist/integration-profile/testers/integration-tester.registry.js.map +1 -0
- package/dist/integration-profile/testers/integration-tester.types.d.ts +55 -0
- package/dist/integration-profile/testers/integration-tester.types.d.ts.map +1 -0
- package/dist/integration-profile/testers/integration-tester.types.js +16 -0
- package/dist/integration-profile/testers/integration-tester.types.js.map +1 -0
- package/dist/integration-profile/testers/messaging.testers.d.ts +3 -0
- package/dist/integration-profile/testers/messaging.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/messaging.testers.js +70 -0
- package/dist/integration-profile/testers/messaging.testers.js.map +1 -0
- package/dist/integration-profile/testers/oauth.testers.d.ts +3 -0
- package/dist/integration-profile/testers/oauth.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/oauth.testers.js +285 -0
- package/dist/integration-profile/testers/oauth.testers.js.map +1 -0
- package/dist/integration-profile/testers/payment.testers.d.ts +3 -0
- package/dist/integration-profile/testers/payment.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/payment.testers.js +169 -0
- package/dist/integration-profile/testers/payment.testers.js.map +1 -0
- package/dist/integration-profile/testers/storage.testers.d.ts +3 -0
- package/dist/integration-profile/testers/storage.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/storage.testers.js +208 -0
- package/dist/integration-profile/testers/storage.testers.js.map +1 -0
- package/dist/language/en.json +4 -2
- package/dist/language/pt.json +4 -2
- package/dist/leaked-password/leaked-password.controller.d.ts +24 -0
- package/dist/leaked-password/leaked-password.controller.d.ts.map +1 -0
- package/dist/leaked-password/leaked-password.controller.js +78 -0
- package/dist/leaked-password/leaked-password.controller.js.map +1 -0
- package/dist/leaked-password/leaked-password.module.d.ts +8 -0
- package/dist/leaked-password/leaked-password.module.d.ts.map +1 -0
- package/dist/leaked-password/leaked-password.module.js +31 -0
- package/dist/leaked-password/leaked-password.module.js.map +1 -0
- package/dist/leaked-password/leaked-password.service.d.ts +64 -0
- package/dist/leaked-password/leaked-password.service.d.ts.map +1 -0
- package/dist/leaked-password/leaked-password.service.js +218 -0
- package/dist/leaked-password/leaked-password.service.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/preview.dto.d.ts +18 -0
- package/dist/mail/dto/preview.dto.d.ts.map +1 -0
- package/dist/mail/dto/preview.dto.js +66 -0
- package/dist/mail/dto/preview.dto.js.map +1 -0
- package/dist/mail/dto/send.dto.d.ts +7 -0
- package/dist/mail/dto/send.dto.d.ts.map +1 -1
- package/dist/mail/dto/send.dto.js +10 -0
- package/dist/mail/dto/send.dto.js.map +1 -1
- package/dist/mail/mail.controller.d.ts +4 -0
- package/dist/mail/mail.controller.d.ts.map +1 -1
- package/dist/mail/mail.controller.js +16 -2
- package/dist/mail/mail.controller.js.map +1 -1
- package/dist/mail/mail.service.d.ts +23 -2
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +102 -13
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mail-layout/dto/update.dto.d.ts +17 -0
- package/dist/mail-layout/dto/update.dto.d.ts.map +1 -0
- package/dist/mail-layout/dto/update.dto.js +27 -0
- package/dist/mail-layout/dto/update.dto.js.map +1 -0
- package/dist/mail-layout/mail-layout.controller.d.ts +15 -0
- package/dist/mail-layout/mail-layout.controller.d.ts.map +1 -0
- package/dist/mail-layout/mail-layout.controller.js +71 -0
- package/dist/mail-layout/mail-layout.controller.js.map +1 -0
- package/dist/mail-layout/mail-layout.module.d.ts +3 -0
- package/dist/mail-layout/mail-layout.module.d.ts.map +1 -0
- package/dist/mail-layout/mail-layout.module.js +35 -0
- package/dist/mail-layout/mail-layout.module.js.map +1 -0
- package/dist/mail-layout/mail-layout.service.d.ts +27 -0
- package/dist/mail-layout/mail-layout.service.d.ts.map +1 -0
- package/dist/mail-layout/mail-layout.service.js +80 -0
- package/dist/mail-layout/mail-layout.service.js.map +1 -0
- package/dist/mcp-chat/mcp-chat.controller.d.ts +2 -2
- package/dist/mcp-chat/mcp-chat.service.d.ts +24 -2
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +80 -24
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/menu/menu.controller.d.ts +3 -3
- package/dist/menu/menu.service.d.ts +3 -3
- package/dist/notification/notification.controller.d.ts +12 -12
- package/dist/notification/notification.service.d.ts +12 -12
- package/dist/oauth/oauth-token-broker.service.d.ts +72 -0
- package/dist/oauth/oauth-token-broker.service.d.ts.map +1 -0
- package/dist/oauth/oauth-token-broker.service.js +258 -0
- package/dist/oauth/oauth-token-broker.service.js.map +1 -0
- package/dist/oauth/oauth.module.d.ts.map +1 -1
- package/dist/oauth/oauth.module.js +3 -1
- package/dist/oauth/oauth.module.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +2 -0
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +6 -3
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/pdf/pdf.service.d.ts +8 -0
- package/dist/pdf/pdf.service.d.ts.map +1 -1
- package/dist/pdf/pdf.service.js +52 -0
- package/dist/pdf/pdf.service.js.map +1 -1
- package/dist/presence/presence.controller.d.ts +16 -0
- package/dist/presence/presence.controller.d.ts.map +1 -0
- package/dist/presence/presence.controller.js +60 -0
- package/dist/presence/presence.controller.js.map +1 -0
- package/dist/presence/presence.listener.d.ts +29 -0
- package/dist/presence/presence.listener.d.ts.map +1 -0
- package/dist/presence/presence.listener.js +82 -0
- package/dist/presence/presence.listener.js.map +1 -0
- package/dist/presence/presence.module.d.ts +3 -0
- package/dist/presence/presence.module.d.ts.map +1 -0
- package/dist/presence/presence.module.js +32 -0
- package/dist/presence/presence.module.js.map +1 -0
- package/dist/presence/presence.service.d.ts +42 -0
- package/dist/presence/presence.service.d.ts.map +1 -0
- package/dist/presence/presence.service.js +147 -0
- package/dist/presence/presence.service.js.map +1 -0
- package/dist/profile/dto/delete-account.dto.d.ts +8 -0
- package/dist/profile/dto/delete-account.dto.d.ts.map +1 -0
- package/dist/profile/dto/delete-account.dto.js +22 -0
- package/dist/profile/dto/delete-account.dto.js.map +1 -0
- package/dist/profile/events/profile-account-deleted.event.d.ts +12 -0
- package/dist/profile/events/profile-account-deleted.event.d.ts.map +1 -0
- package/dist/profile/events/profile-account-deleted.event.js +17 -0
- package/dist/profile/events/profile-account-deleted.event.js.map +1 -0
- package/dist/profile/profile.controller.d.ts +21 -15
- package/dist/profile/profile.controller.d.ts.map +1 -1
- package/dist/profile/profile.controller.js +75 -46
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/profile/profile.service.d.ts +30 -18
- package/dist/profile/profile.service.d.ts.map +1 -1
- package/dist/profile/profile.service.js +113 -37
- package/dist/profile/profile.service.js.map +1 -1
- package/dist/realtime/realtime.gateway.d.ts +48 -0
- package/dist/realtime/realtime.gateway.d.ts.map +1 -0
- package/dist/realtime/realtime.gateway.js +156 -0
- package/dist/realtime/realtime.gateway.js.map +1 -0
- package/dist/realtime/realtime.module.d.ts +8 -0
- package/dist/realtime/realtime.module.d.ts.map +1 -0
- package/dist/realtime/realtime.module.js +29 -0
- package/dist/realtime/realtime.module.js.map +1 -0
- package/dist/realtime/realtime.service.d.ts +51 -0
- package/dist/realtime/realtime.service.d.ts.map +1 -0
- package/dist/realtime/realtime.service.js +177 -0
- package/dist/realtime/realtime.service.js.map +1 -0
- package/dist/redis/redis-pubsub.d.ts +27 -0
- package/dist/redis/redis-pubsub.d.ts.map +1 -0
- package/dist/redis/redis-pubsub.js +140 -0
- package/dist/redis/redis-pubsub.js.map +1 -0
- package/dist/role/role.controller.d.ts +3 -3
- package/dist/role/role.service.d.ts +3 -3
- package/dist/setting/dto/create.dto.d.ts.map +1 -1
- package/dist/setting/dto/create.dto.js +9 -2
- package/dist/setting/dto/create.dto.js.map +1 -1
- package/dist/setting/setting.controller.d.ts +5 -5
- package/dist/setting/setting.service.d.ts +8 -5
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +25 -1
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/user/dto/create-with-email-and-password.dto.d.ts +2 -0
- package/dist/user/dto/create-with-email-and-password.dto.d.ts.map +1 -1
- package/dist/user/dto/create-with-email-and-password.dto.js +5 -0
- package/dist/user/dto/create-with-email-and-password.dto.js.map +1 -1
- package/dist/user/dto/query-user-mail-list.dto.d.ts +5 -0
- package/dist/user/dto/query-user-mail-list.dto.d.ts.map +1 -0
- package/dist/user/dto/query-user-mail-list.dto.js +25 -0
- package/dist/user/dto/query-user-mail-list.dto.js.map +1 -0
- package/dist/user/user-credential.util.d.ts +19 -0
- package/dist/user/user-credential.util.d.ts.map +1 -0
- package/dist/user/user-credential.util.js +32 -0
- package/dist/user/user-credential.util.js.map +1 -0
- package/dist/user/user.controller.d.ts +17 -5
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.controller.js +18 -3
- package/dist/user/user.controller.js.map +1 -1
- package/dist/user/user.service.d.ts +28 -6
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +204 -13
- package/dist/user/user.service.js.map +1 -1
- package/dist/validators/is-strong-password-with-settings.validator.d.ts.map +1 -1
- package/dist/validators/is-strong-password-with-settings.validator.js +11 -0
- package/dist/validators/is-strong-password-with-settings.validator.js.map +1 -1
- package/dist/validators/service-locator.d.ts +9 -0
- package/dist/validators/service-locator.d.ts.map +1 -1
- package/dist/validators/service-locator.js +12 -0
- package/dist/validators/service-locator.js.map +1 -1
- package/dist/whatsapp-sender/whatsapp-sender.module.d.ts +3 -0
- package/dist/whatsapp-sender/whatsapp-sender.module.d.ts.map +1 -0
- package/dist/whatsapp-sender/whatsapp-sender.module.js +23 -0
- package/dist/whatsapp-sender/whatsapp-sender.module.js.map +1 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +50 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.js +224 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -0
- package/hedhog/data/integration_provider.yaml +16 -0
- package/hedhog/data/mail.yaml +88 -61
- package/hedhog/data/mail_layout.yaml +188 -0
- package/hedhog/data/menu.yaml +67 -3
- package/hedhog/data/route.yaml +135 -0
- package/hedhog/data/setting_group.yaml +139 -1
- package/hedhog/frontend/app/account/components/mfa-setup-dialog.tsx.ejs +36 -0
- package/hedhog/frontend/app/account/components/two-factor-auth.tsx.ejs +2 -0
- package/hedhog/frontend/app/account/hooks/use-mfa-setup.ts.ejs +10 -7
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +7 -4
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +580 -0
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-preview.tsx.ejs +150 -0
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +199 -0
- package/hedhog/frontend/app/ai_instruction/_components/prompt-diff.tsx.ejs +63 -0
- package/hedhog/frontend/app/ai_instruction/_lib/line-diff.spec.ts.ejs +59 -0
- package/hedhog/frontend/app/ai_instruction/_lib/line-diff.ts.ejs +72 -0
- package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.spec.ts.ejs +170 -0
- package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.ts.ejs +167 -0
- package/hedhog/frontend/app/ai_instruction/_lib/types.ts.ejs +99 -0
- package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +422 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +51 -4
- package/hedhog/frontend/app/incidents/page.tsx.ejs +400 -0
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +153 -84
- package/hedhog/frontend/app/mail/layout/page.tsx.ejs +344 -0
- package/hedhog/frontend/app/mail/template/page.tsx.ejs +155 -121
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +129 -17
- package/hedhog/frontend/app/pages/_components/page-delete-dialog.tsx.ejs +343 -0
- package/hedhog/frontend/app/pages/_components/page-detail-sheet.tsx.ejs +438 -0
- package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1009 -0
- package/hedhog/frontend/app/pages/_components/system-page-types.ts.ejs +56 -0
- package/hedhog/frontend/app/pages/_components/use-system-pages.ts.ejs +171 -0
- package/hedhog/frontend/app/pages/page.tsx.ejs +514 -0
- package/hedhog/frontend/app/users/page.tsx.ejs +119 -13
- package/hedhog/frontend/app/users/user-activity-timeline.tsx.ejs +231 -0
- package/hedhog/frontend/app/users/user-mails.tsx.ejs +399 -0
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +60 -75
- package/hedhog/frontend/messages/en.json +499 -3
- package/hedhog/frontend/messages/pt.json +499 -3
- package/hedhog/table/ai_agent.yaml +1 -0
- package/hedhog/table/ai_instruction.yaml +15 -0
- package/hedhog/table/leaked_password.yaml +18 -0
- package/hedhog/table/mail_layout.yaml +35 -0
- package/hedhog/table/mail_var.yaml +4 -0
- package/hedhog/table/setting.yaml +1 -0
- package/hedhog/table/system_incident.yaml +59 -0
- package/hedhog/table/user_presence.yaml +36 -0
- package/package.json +8 -4
- package/src/access-log/access-log.interceptor.ts +4 -2
- package/src/ai/ai-attachment.fragments.spec.ts +319 -0
- package/src/ai/ai-attachment.fragments.ts +35 -0
- package/src/ai/ai.prompts.ts +38 -0
- package/src/ai/ai.service.spec.ts +280 -0
- package/src/ai/ai.service.ts +338 -82
- package/src/ai/dto/chat.dto.ts +33 -3
- package/src/ai/dto/create-agent.dto.ts +2 -2
- package/src/ai/dto/update-agent.dto.ts +2 -2
- package/src/ai-instruction/ai-instruction.controller.ts +40 -9
- package/src/ai-instruction/ai-instruction.module.ts +13 -2
- package/src/ai-instruction/ai-instruction.service.spec.ts +658 -0
- package/src/ai-instruction/ai-instruction.service.ts +661 -62
- package/src/ai-instruction/ai-prompt-builder.service.ts +10 -1
- package/src/ai-instruction/ai-prompt-registry.ts +87 -0
- package/src/ai-instruction/ai-prompt-resolver.service.spec.ts +375 -0
- package/src/ai-instruction/ai-prompt-resolver.service.ts +295 -0
- package/src/ai-instruction/ai-prompt-template.util.spec.ts +162 -0
- package/src/ai-instruction/ai-prompt-template.util.ts +199 -0
- package/src/ai-instruction/dto/create-ai-instruction.dto.ts +39 -3
- package/src/ai-instruction/dto/preview-ai-instruction.dto.ts +26 -0
- package/src/ai-instruction/dto/update-ai-instruction.dto.ts +42 -1
- package/src/ai-instruction/types/ai-instruction.types.ts +24 -1
- package/src/auth/auth.controller.ts +31 -5
- package/src/auth/auth.service.spec.ts +3 -1
- package/src/auth/auth.service.ts +101 -36
- package/src/captcha/captcha.module.ts +10 -0
- package/src/captcha/captcha.service.spec.ts +210 -0
- package/src/captcha/captcha.service.ts +191 -0
- package/src/challenge/challenge.service.spec.ts +39 -4
- package/src/challenge/challenge.service.ts +72 -17
- package/src/core.module.ts +27 -1
- package/src/file/file.service.spec.ts +105 -0
- package/src/file/file.service.ts +60 -3
- package/src/incident/incident-notifier.service.spec.ts +205 -0
- package/src/incident/incident-notifier.service.ts +241 -0
- package/src/incident/incident.controller.ts +38 -0
- package/src/incident/incident.module.ts +19 -0
- package/src/incident/incident.service.spec.ts +150 -0
- package/src/incident/incident.service.ts +209 -0
- package/src/index.ts +37 -0
- package/src/integration-profile/dto/test.dto.ts +19 -0
- package/src/integration-profile/integration-profile.controller.ts +10 -1
- package/src/integration-profile/integration-profile.module.spec.ts +51 -0
- package/src/integration-profile/integration-profile.module.ts +23 -4
- package/src/integration-profile/integration-profile.secrets.ts +9 -1
- package/src/integration-profile/integration-profile.service.spec.ts +279 -0
- package/src/integration-profile/integration-profile.service.ts +120 -124
- package/src/integration-profile/integration-profile.utils.spec.ts +22 -0
- package/src/integration-profile/integration-profile.utils.ts +40 -3
- package/src/integration-profile/testers/ai.testers.ts +165 -0
- package/src/integration-profile/testers/captcha.testers.spec.ts +92 -0
- package/src/integration-profile/testers/captcha.testers.ts +139 -0
- package/src/integration-profile/testers/email.testers.ts +161 -0
- package/src/integration-profile/testers/http-probe.spec.ts +153 -0
- package/src/integration-profile/testers/http-probe.ts +171 -0
- package/src/integration-profile/testers/index.ts +30 -0
- package/src/integration-profile/testers/infrastructure.testers.ts +122 -0
- package/src/integration-profile/testers/integration-tester.registry.spec.ts +75 -0
- package/src/integration-profile/testers/integration-tester.registry.ts +43 -0
- package/src/integration-profile/testers/integration-tester.types.ts +61 -0
- package/src/integration-profile/testers/messaging.testers.ts +102 -0
- package/src/integration-profile/testers/oauth.testers.spec.ts +220 -0
- package/src/integration-profile/testers/oauth.testers.ts +305 -0
- package/src/integration-profile/testers/payment.testers.ts +185 -0
- package/src/integration-profile/testers/remaining.testers.spec.ts +401 -0
- package/src/integration-profile/testers/storage.testers.spec.ts +185 -0
- package/src/integration-profile/testers/storage.testers.ts +226 -0
- package/src/integration-profile/testers/tester-coverage.spec.ts +58 -0
- package/src/language/en.json +4 -2
- package/src/language/pt.json +4 -2
- package/src/leaked-password/README.md +83 -0
- package/src/leaked-password/leaked-password.controller.ts +52 -0
- package/src/leaked-password/leaked-password.module.ts +18 -0
- package/src/leaked-password/leaked-password.service.ts +242 -0
- package/src/leaked-password/seed/build-seed-sql.mjs +180 -0
- package/src/leaked-password/seed/common-passwords.txt +335 -0
- package/src/mail/dto/preview.dto.ts +50 -0
- package/src/mail/dto/send.dto.ts +14 -1
- package/src/mail/mail-template.spec.ts +197 -0
- package/src/mail/mail.controller.ts +9 -2
- package/src/mail/mail.service.spec.ts +116 -1
- package/src/mail/mail.service.ts +118 -12
- package/src/mail-layout/dto/update.dto.ts +19 -0
- package/src/mail-layout/mail-layout.controller.ts +47 -0
- package/src/mail-layout/mail-layout.module.ts +22 -0
- package/src/mail-layout/mail-layout.service.ts +94 -0
- package/src/mcp-chat/mcp-chat.service.spec.ts +236 -0
- package/src/mcp-chat/mcp-chat.service.ts +122 -26
- package/src/oauth/oauth-token-broker.service.spec.ts +172 -0
- package/src/oauth/oauth-token-broker.service.ts +363 -0
- package/src/oauth/oauth.module.ts +3 -1
- package/src/oauth/oauth.service.ts +8 -2
- package/src/pdf/pdf.service.ts +75 -0
- package/src/presence/presence.controller.ts +29 -0
- package/src/presence/presence.listener.ts +53 -0
- package/src/presence/presence.module.ts +19 -0
- package/src/presence/presence.service.spec.ts +97 -0
- package/src/presence/presence.service.ts +160 -0
- package/src/profile/dto/delete-account.dto.ts +11 -0
- package/src/profile/events/profile-account-deleted.event.ts +13 -0
- package/src/profile/profile.controller.ts +46 -34
- package/src/profile/profile.service.ts +138 -38
- package/src/realtime/realtime.gateway.ts +138 -0
- package/src/realtime/realtime.module.ts +16 -0
- package/src/realtime/realtime.service.spec.ts +50 -0
- package/src/realtime/realtime.service.ts +187 -0
- package/src/redis/redis-pubsub.ts +179 -0
- package/src/setting/dto/create.dto.ts +13 -2
- package/src/setting/setting.service.spec.ts +56 -0
- package/src/setting/setting.service.ts +29 -1
- package/src/user/dto/create-with-email-and-password.dto.ts +6 -1
- package/src/user/dto/query-user-mail-list.dto.ts +10 -0
- package/src/user/user-credential.util.ts +35 -0
- package/src/user/user.controller.ts +17 -2
- package/src/user/user.service.spec.ts +153 -0
- package/src/user/user.service.ts +255 -12
- package/src/validators/is-strong-password-with-settings.validator.ts +12 -0
- package/src/validators/service-locator.ts +15 -0
- package/src/whatsapp-sender/whatsapp-sender.module.ts +10 -0
- package/src/whatsapp-sender/whatsapp-sender.service.ts +313 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { HeadBucketCommand, S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import { BlobServiceClient, StorageSharedKeyCredential } from '@azure/storage-blob';
|
|
3
|
+
import { Storage } from '@google-cloud/storage';
|
|
4
|
+
import { access, constants } from 'node:fs/promises';
|
|
5
|
+
import { assertHttpUrl, fail, pass, requireFields, str } from './http-probe';
|
|
6
|
+
import { IntegrationTester, IntegrationTestOutcome } from './integration-tester.types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Testadores dos providers de storage.
|
|
10
|
+
*
|
|
11
|
+
* Todos usam uma operação de LEITURA (HeadBucket, getMetadata, getProperties): provam
|
|
12
|
+
* credencial, existência do bucket/container e permissão sem escrever nada na conta
|
|
13
|
+
* do cliente.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Traduz o erro dos SDKs S3 em algo que o operador consiga agir. */
|
|
17
|
+
async function headS3Bucket(
|
|
18
|
+
client: S3Client,
|
|
19
|
+
bucket: string,
|
|
20
|
+
label: string,
|
|
21
|
+
signal: AbortSignal,
|
|
22
|
+
): Promise<IntegrationTestOutcome> {
|
|
23
|
+
try {
|
|
24
|
+
await client.send(new HeadBucketCommand({ Bucket: bucket }), {
|
|
25
|
+
abortSignal: signal,
|
|
26
|
+
});
|
|
27
|
+
return pass(label);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
const err = error as {
|
|
30
|
+
name?: string;
|
|
31
|
+
message?: string;
|
|
32
|
+
$metadata?: { httpStatusCode?: number };
|
|
33
|
+
};
|
|
34
|
+
const status = err?.$metadata?.httpStatusCode;
|
|
35
|
+
const name = String(err?.name ?? '');
|
|
36
|
+
|
|
37
|
+
if (name === 'InvalidAccessKeyId' || status === 401) {
|
|
38
|
+
return fail('Invalid access key ID.');
|
|
39
|
+
}
|
|
40
|
+
if (name === 'SignatureDoesNotMatch') {
|
|
41
|
+
return fail('Invalid secret access key.');
|
|
42
|
+
}
|
|
43
|
+
if (name === 'NotFound' || status === 404) {
|
|
44
|
+
return fail(`Bucket "${bucket}" was not found.`);
|
|
45
|
+
}
|
|
46
|
+
if (name === 'Forbidden' || status === 403) {
|
|
47
|
+
return fail(
|
|
48
|
+
`These credentials have no permission to access the bucket "${bucket}".`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
if (name === 'PermanentRedirect' || status === 301) {
|
|
52
|
+
return fail(`Bucket "${bucket}" lives in another region.`);
|
|
53
|
+
}
|
|
54
|
+
return fail(String(err?.message ?? 'Could not reach the bucket.'));
|
|
55
|
+
} finally {
|
|
56
|
+
client.destroy();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const localTester: IntegrationTester = {
|
|
61
|
+
providerSlug: 'local',
|
|
62
|
+
test: async (config) => {
|
|
63
|
+
const basePath = str(config, 'base_path') || 'storage';
|
|
64
|
+
try {
|
|
65
|
+
// Só checa permissão — escrever um arquivo de teste sujaria o storage do cliente.
|
|
66
|
+
await access(basePath, constants.R_OK | constants.W_OK);
|
|
67
|
+
return pass(basePath);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
const code = String((error as { code?: string })?.code ?? '');
|
|
70
|
+
if (code === 'ENOENT') {
|
|
71
|
+
return fail(`The directory "${basePath}" does not exist.`);
|
|
72
|
+
}
|
|
73
|
+
if (code === 'EACCES' || code === 'EPERM') {
|
|
74
|
+
return fail(`No read/write permission on the directory "${basePath}".`);
|
|
75
|
+
}
|
|
76
|
+
return fail(`Could not access the directory "${basePath}".`);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const s3Tester: IntegrationTester = {
|
|
82
|
+
providerSlug: 's3',
|
|
83
|
+
test: async (config, ctx) => {
|
|
84
|
+
const missing = requireFields(config, [
|
|
85
|
+
['access_key_id', 'Access key ID'],
|
|
86
|
+
['secret_access_key', 'Secret access key'],
|
|
87
|
+
['bucket', 'Bucket'],
|
|
88
|
+
]);
|
|
89
|
+
if (missing) return missing;
|
|
90
|
+
|
|
91
|
+
const region = str(config, 'region') || 'us-east-1';
|
|
92
|
+
const bucket = str(config, 'bucket');
|
|
93
|
+
const sessionToken = String(config.session_token ?? '').trim();
|
|
94
|
+
|
|
95
|
+
const client = new S3Client({
|
|
96
|
+
region,
|
|
97
|
+
credentials: {
|
|
98
|
+
accessKeyId: str(config, 'access_key_id'),
|
|
99
|
+
secretAccessKey: String(config.secret_access_key ?? ''),
|
|
100
|
+
...(sessionToken ? { sessionToken } : {}),
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return headS3Bucket(client, bucket, `${bucket} (${region})`, ctx.signal);
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const s3CompatibleTester: IntegrationTester = {
|
|
109
|
+
providerSlug: 's3-compatible',
|
|
110
|
+
test: async (config, ctx) => {
|
|
111
|
+
const missing = requireFields(config, [
|
|
112
|
+
['endpoint', 'Endpoint'],
|
|
113
|
+
['access_key_id', 'Access key ID'],
|
|
114
|
+
['secret_access_key', 'Secret access key'],
|
|
115
|
+
['bucket', 'Bucket'],
|
|
116
|
+
]);
|
|
117
|
+
if (missing) return missing;
|
|
118
|
+
|
|
119
|
+
const endpoint = assertHttpUrl(str(config, 'endpoint'), 'Endpoint');
|
|
120
|
+
const bucket = str(config, 'bucket');
|
|
121
|
+
const region = str(config, 'region') || 'us-east-1';
|
|
122
|
+
|
|
123
|
+
const client = new S3Client({
|
|
124
|
+
region,
|
|
125
|
+
endpoint: endpoint.origin,
|
|
126
|
+
// Provedores compatíveis (MinIO, Ceph) raramente resolvem bucket por subdomínio.
|
|
127
|
+
forcePathStyle: true,
|
|
128
|
+
credentials: {
|
|
129
|
+
accessKeyId: str(config, 'access_key_id'),
|
|
130
|
+
secretAccessKey: String(config.secret_access_key ?? ''),
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return headS3Bucket(client, bucket, `${bucket} @ ${endpoint.host}`, ctx.signal);
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const gcsTester: IntegrationTester = {
|
|
139
|
+
providerSlug: 'gcs',
|
|
140
|
+
test: async (config) => {
|
|
141
|
+
const missing = requireFields(config, [
|
|
142
|
+
['key_file_json', 'Service account JSON'],
|
|
143
|
+
['bucket', 'Bucket'],
|
|
144
|
+
]);
|
|
145
|
+
if (missing) return missing;
|
|
146
|
+
|
|
147
|
+
let credentials: { project_id?: string; client_email?: string };
|
|
148
|
+
try {
|
|
149
|
+
credentials = JSON.parse(String(config.key_file_json ?? ''));
|
|
150
|
+
} catch {
|
|
151
|
+
return fail('The service account JSON is not valid JSON.');
|
|
152
|
+
}
|
|
153
|
+
if (!credentials?.client_email) {
|
|
154
|
+
return fail('The service account JSON has no "client_email".');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const bucket = str(config, 'bucket');
|
|
158
|
+
try {
|
|
159
|
+
const storage = new Storage({
|
|
160
|
+
projectId: credentials.project_id,
|
|
161
|
+
credentials: credentials as Record<string, string>,
|
|
162
|
+
});
|
|
163
|
+
const [metadata] = await storage.bucket(bucket).getMetadata();
|
|
164
|
+
return pass(`${bucket}${metadata?.location ? ` (${metadata.location})` : ''}`);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
const err = error as { code?: number; message?: string };
|
|
167
|
+
if (err?.code === 404) return fail(`Bucket "${bucket}" was not found.`);
|
|
168
|
+
if (err?.code === 403) {
|
|
169
|
+
return fail(
|
|
170
|
+
`The service account has no permission to access the bucket "${bucket}".`,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
if (err?.code === 401) return fail('The service account key was rejected.');
|
|
174
|
+
return fail(String(err?.message ?? 'Could not reach the bucket.'));
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const azureBlobTester: IntegrationTester = {
|
|
180
|
+
providerSlug: 'azure-blob',
|
|
181
|
+
test: async (config) => {
|
|
182
|
+
const missing = requireFields(config, [
|
|
183
|
+
['account', 'Storage account'],
|
|
184
|
+
['key', 'Access key'],
|
|
185
|
+
['container', 'Container'],
|
|
186
|
+
]);
|
|
187
|
+
if (missing) return missing;
|
|
188
|
+
|
|
189
|
+
const account = str(config, 'account');
|
|
190
|
+
const container = str(config, 'container');
|
|
191
|
+
|
|
192
|
+
let credential: StorageSharedKeyCredential;
|
|
193
|
+
try {
|
|
194
|
+
credential = new StorageSharedKeyCredential(account, String(config.key ?? ''));
|
|
195
|
+
} catch {
|
|
196
|
+
// O SDK decodifica a chave em base64 na construção.
|
|
197
|
+
return fail('The access key is not a valid Azure storage key.');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const service = new BlobServiceClient(
|
|
202
|
+
`https://${account}.blob.core.windows.net`,
|
|
203
|
+
credential,
|
|
204
|
+
);
|
|
205
|
+
await service.getContainerClient(container).getProperties();
|
|
206
|
+
return pass(`${account}/${container}`);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
const err = error as { statusCode?: number; code?: string; message?: string };
|
|
209
|
+
if (err?.statusCode === 403 || err?.code === 'AuthenticationFailed') {
|
|
210
|
+
return fail('The storage account or access key was rejected.');
|
|
211
|
+
}
|
|
212
|
+
if (err?.statusCode === 404 || err?.code === 'ContainerNotFound') {
|
|
213
|
+
return fail(`Container "${container}" was not found.`);
|
|
214
|
+
}
|
|
215
|
+
return fail(String(err?.message ?? 'Could not reach the container.'));
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export const STORAGE_TESTERS: IntegrationTester[] = [
|
|
221
|
+
localTester,
|
|
222
|
+
s3Tester,
|
|
223
|
+
s3CompatibleTester,
|
|
224
|
+
gcsTester,
|
|
225
|
+
azureBlobTester,
|
|
226
|
+
];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
import { INTEGRATION_SECRET_KEYS } from '../integration-profile.secrets';
|
|
3
|
+
import { BUILTIN_INTEGRATION_TESTERS } from './index';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* TRAVA ANTI-DRIFT, no mesmo espírito de integration-profile.secrets.spec.ts.
|
|
7
|
+
*
|
|
8
|
+
* Um provider novo entra no catálogo por YAML e ganha campos no form do admin. Sem
|
|
9
|
+
* este teste, o botão "Testar conexão" simplesmente responderia "não disponível para
|
|
10
|
+
* este provedor" — uma falha silenciosa, que só aparece quando alguém tenta usar.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Providers cujo tester vive em outra library (não pode ser embutido no core). */
|
|
14
|
+
const EXTERNAL_PROVIDERS = new Set([
|
|
15
|
+
// Abrir o certificado A1 é código do domínio fiscal: o tester se registra pelo
|
|
16
|
+
// NfseNationalModule (libraries/fiscal).
|
|
17
|
+
'nfse-national',
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
/** Providers legítimos sem nenhum campo secreto. */
|
|
21
|
+
const PROVIDERS_WITHOUT_SECRETS = new Set([
|
|
22
|
+
// Storage no disco local: só um caminho, sem credencial.
|
|
23
|
+
'local',
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
const registeredSlugs = new Set(
|
|
27
|
+
BUILTIN_INTEGRATION_TESTERS.map((tester) => tester.providerSlug),
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
describe('cobertura dos testers de conexão', () => {
|
|
31
|
+
it('todo provider com credenciais tem um tester (embutido ou de outra library)', () => {
|
|
32
|
+
const missing = Object.keys(INTEGRATION_SECRET_KEYS).filter(
|
|
33
|
+
(slug) => !registeredSlugs.has(slug) && !EXTERNAL_PROVIDERS.has(slug),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
expect(missing).toEqual([]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('todo tester embutido corresponde a um provider conhecido', () => {
|
|
40
|
+
const unknown = [...registeredSlugs].filter(
|
|
41
|
+
(slug) =>
|
|
42
|
+
!(slug in INTEGRATION_SECRET_KEYS) && !PROVIDERS_WITHOUT_SECRETS.has(slug),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
expect(unknown).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('não há dois testers para o mesmo provider', () => {
|
|
49
|
+
expect(registeredSlugs.size).toBe(BUILTIN_INTEGRATION_TESTERS.length);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('todo tester expõe um providerSlug normalizado e uma função test', () => {
|
|
53
|
+
for (const tester of BUILTIN_INTEGRATION_TESTERS) {
|
|
54
|
+
expect(tester.providerSlug).toBe(tester.providerSlug.toLowerCase().trim());
|
|
55
|
+
expect(typeof tester.test).toBe('function');
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
package/src/language/en.json
CHANGED
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
},
|
|
27
27
|
"forgot": {
|
|
28
28
|
"rateLimit": "Too many requests. Please try again later.",
|
|
29
|
-
"userNotFound": "User not found."
|
|
29
|
+
"userNotFound": "User not found.",
|
|
30
|
+
"noPassword": "This account does not have a password set. Please sign in using your organization's login provider (e.g. Microsoft)."
|
|
30
31
|
},
|
|
31
32
|
"challenge": {
|
|
32
33
|
"invalidOrExpired": "The provided code is invalid or has expired."
|
|
@@ -70,7 +71,8 @@
|
|
|
70
71
|
"minLowercase": "Password must contain at least {minLowercase} lowercase letter(s).",
|
|
71
72
|
"minUppercase": "Password must contain at least {minUppercase} uppercase letter(s).",
|
|
72
73
|
"minNumbers": "Password must contain at least {minNumbers} number(s).",
|
|
73
|
-
"minSymbols": "Password must contain at least {minSymbols} special character(s)."
|
|
74
|
+
"minSymbols": "Password must contain at least {minSymbols} special character(s).",
|
|
75
|
+
"leaked": "This password appears in known data breaches. Please choose another one."
|
|
74
76
|
},
|
|
75
77
|
"createUser": {
|
|
76
78
|
"nameRequired": "Name is required."
|
package/src/language/pt.json
CHANGED
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
},
|
|
27
27
|
"forgot": {
|
|
28
28
|
"rateLimit": "Muitas solicitações. Por favor, tente novamente mais tarde.",
|
|
29
|
-
"userNotFound": "Usuário não encontrado."
|
|
29
|
+
"userNotFound": "Usuário não encontrado.",
|
|
30
|
+
"noPassword": "Esta conta não possui senha cadastrada. Faça login utilizando o provedor de acesso da sua organização (ex: Microsoft)."
|
|
30
31
|
},
|
|
31
32
|
"challenge": {
|
|
32
33
|
"invalidOrExpired": "O código informado é inválido ou expirou."
|
|
@@ -70,7 +71,8 @@
|
|
|
70
71
|
"minLowercase": "A senha deve conter pelo menos {minLowercase} letra(s) minúscula(s).",
|
|
71
72
|
"minUppercase": "A senha deve conter pelo menos {minUppercase} letra(s) maiúscula(s).",
|
|
72
73
|
"minNumbers": "A senha deve conter pelo menos {minNumbers} número(s).",
|
|
73
|
-
"minSymbols": "A senha deve conter pelo menos {minSymbols} caractere(s) especial(is)."
|
|
74
|
+
"minSymbols": "A senha deve conter pelo menos {minSymbols} caractere(s) especial(is).",
|
|
75
|
+
"leaked": "Esta senha aparece em vazamentos de dados conhecidos. Escolha outra."
|
|
74
76
|
},
|
|
75
77
|
"createUser": {
|
|
76
78
|
"nameRequired": "Nome é obrigatório."
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Senhas vazadas conhecidas
|
|
2
|
+
|
|
3
|
+
Corpus de hashes SHA-1 de senhas que aparecem em vazamentos públicos, com duas
|
|
4
|
+
leituras bem diferentes.
|
|
5
|
+
|
|
6
|
+
## Por que bloom filter, e não uma consulta
|
|
7
|
+
|
|
8
|
+
O cofre (`libraries/vaults`) é criptografado ponta a ponta: o servidor nunca vê
|
|
9
|
+
uma senha guardada. Isso descarta o desenho óbvio ("o cliente pergunta se a
|
|
10
|
+
senha X vazou") e também o modelo de k-anonimato do Pwned Passwords, em que o
|
|
11
|
+
cliente manda o prefixo do hash — com corpus pequeno, um prefixo já identifica
|
|
12
|
+
quase unicamente a senha.
|
|
13
|
+
|
|
14
|
+
Então o servidor entrega o corpus inteiro como bloom filter e o navegador
|
|
15
|
+
responde sozinho. Nada sobre a senha sai do cliente. O preço é a taxa de falso
|
|
16
|
+
positivo do filtro (0,1%): uma senha pode ser apontada como vazada sem estar no
|
|
17
|
+
corpus, nunca o contrário.
|
|
18
|
+
|
|
19
|
+
| Caminho | Quem usa | Como |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| `GET /leaked-password/filter` | cofre, medidor de força do formulário | baixa o filtro, testa local |
|
|
22
|
+
| `LeakedPasswordService.isLeaked()` | validador de senha de **login** | consulta direta no banco |
|
|
23
|
+
|
|
24
|
+
A consulta direta só vale onde a senha em claro já passa pelo servidor de
|
|
25
|
+
qualquer forma (cadastro e troca de senha do sistema). Nunca use `isLeaked()`
|
|
26
|
+
com senha de cofre.
|
|
27
|
+
|
|
28
|
+
Tamanho do filtro: `-n·ln(p)/(ln2)²` bits. ~18 mil hashes ⇒ ~32KB; 1M ⇒ ~1,8MB.
|
|
29
|
+
Ele é montado sob demanda e fica em memória enquanto a versão do corpus não muda
|
|
30
|
+
(`count` + `created_at` mais recente), com `ETag` para o navegador revalidar de
|
|
31
|
+
graça.
|
|
32
|
+
|
|
33
|
+
## O que já vem semeado
|
|
34
|
+
|
|
35
|
+
A migration `20260729180000_core_leaked_password` insere ~8,7 mil hashes gerados
|
|
36
|
+
de [`seed/common-passwords.txt`](./seed/common-passwords.txt) — as senhas
|
|
37
|
+
notórias de toda publicação anual de "senhas mais usadas", os equivalentes
|
|
38
|
+
brasileiros, e a expansão delas nos padrões que dominam vazamento (sufixo
|
|
39
|
+
numérico, ano, capitalização, leet).
|
|
40
|
+
|
|
41
|
+
**Isto é uma base curada, não o top-N do Have I Been Pwned.** Cobre o reuso
|
|
42
|
+
óbvio; cobertura real vem do import.
|
|
43
|
+
|
|
44
|
+
O SHA-1 do seed vai calculado em hex na migration porque o `pgcrypto` está
|
|
45
|
+
disponível mas não instalado no cluster, e `CREATE EXTENSION` exigiria
|
|
46
|
+
superusuário em produção.
|
|
47
|
+
|
|
48
|
+
Para regerar depois de mexer na lista base (criando uma migration nova — as
|
|
49
|
+
existentes nunca são reescritas):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node libraries/core/src/leaked-password/seed/build-seed-sql.mjs --count # confere o tamanho
|
|
53
|
+
node libraries/core/src/leaked-password/seed/build-seed-sql.mjs > /tmp/seed.sql
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Ampliando o corpus
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# lista base completa (~120 mil, a expansão que não caberia numa migration)
|
|
60
|
+
node libraries/core/src/leaked-password/seed/build-seed-sql.mjs --full --plain > /tmp/base.txt
|
|
61
|
+
pnpm import:leaked-passwords /tmp/base.txt
|
|
62
|
+
|
|
63
|
+
# dump do Pwned Passwords, reduzido às N senhas mais frequentes
|
|
64
|
+
sort -t: -k2 -rn pwnedpasswords.txt | head -1000000 > top1m.txt
|
|
65
|
+
pnpm import:leaked-passwords top1m.txt
|
|
66
|
+
|
|
67
|
+
pnpm import:leaked-passwords arquivo.txt --dry-run # só relata
|
|
68
|
+
pnpm import:leaked-passwords arquivo.txt --limit 50000 # para em N linhas lidas
|
|
69
|
+
pnpm import:leaked-passwords arquivo.txt --min-occurrences 10
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
O import é idempotente (o unique em `hash` + `skipDuplicates` absorvem
|
|
73
|
+
repetição), então reprocessar o mesmo arquivo não faz nada.
|
|
74
|
+
|
|
75
|
+
**Dimensione antes:** o dump completo do Pwned Passwords são ~850M hashes
|
|
76
|
+
(~40GB no Postgres) e não cabe no banco deste projeto. 1M hashes ⇒ ~80MB de
|
|
77
|
+
tabela e índice.
|
|
78
|
+
|
|
79
|
+
## Desligando
|
|
80
|
+
|
|
81
|
+
A setting `password-block-leaked` (grupo de política de senha, padrão ligada)
|
|
82
|
+
controla as duas pontas: desligada, o validador de login para de recusar e o
|
|
83
|
+
cliente nem baixa o filtro.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Role } from '@hed-hog/api';
|
|
2
|
+
import { Controller, Get, Inject, Req, Res, forwardRef } from '@nestjs/common';
|
|
3
|
+
import type { Request, Response } from 'express';
|
|
4
|
+
import { LeakedPasswordService } from './leaked-password.service';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Entrega o bloom filter do corpus de senhas vazadas para o cliente testar as
|
|
8
|
+
* senhas do cofre localmente.
|
|
9
|
+
*
|
|
10
|
+
* É o desenho que mantém a criptografia ponta a ponta: em vez de o navegador
|
|
11
|
+
* perguntar "esta senha vazou?" (revelando a senha, ou pelo menos um prefixo do
|
|
12
|
+
* hash dela), ele baixa o filtro inteiro uma vez e responde sozinho.
|
|
13
|
+
*
|
|
14
|
+
* Autenticado de propósito: o conteúdo é público em essência, mas são MBs por
|
|
15
|
+
* download, e o `If-None-Match` faz o navegador revalidar de graça.
|
|
16
|
+
*/
|
|
17
|
+
@Role()
|
|
18
|
+
@Controller('leaked-password')
|
|
19
|
+
export class LeakedPasswordController {
|
|
20
|
+
constructor(
|
|
21
|
+
@Inject(forwardRef(() => LeakedPasswordService))
|
|
22
|
+
private readonly leakedPasswordService: LeakedPasswordService,
|
|
23
|
+
) {}
|
|
24
|
+
|
|
25
|
+
@Get('filter')
|
|
26
|
+
async filter(@Req() req: Request, @Res() res: Response): Promise<void> {
|
|
27
|
+
const filter = await this.leakedPasswordService.getFilter();
|
|
28
|
+
|
|
29
|
+
if (req.headers['if-none-match'] === filter.etag) {
|
|
30
|
+
res.status(304).end();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
res.set({
|
|
35
|
+
'Content-Type': 'application/octet-stream',
|
|
36
|
+
'Content-Length': String(filter.bytes.length),
|
|
37
|
+
ETag: filter.etag,
|
|
38
|
+
// `must-revalidate` com ETag: o navegador reusa o filtro sem baixar de novo,
|
|
39
|
+
// mas nunca serve corpus velho depois de um import.
|
|
40
|
+
'Cache-Control': 'private, max-age=0, must-revalidate',
|
|
41
|
+
'X-Leaked-Password-Count': String(filter.count),
|
|
42
|
+
});
|
|
43
|
+
res.end(filter.bytes);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Tamanho do corpus, para a tela de configuração mostrar o que está ativo. */
|
|
47
|
+
@Get('stats')
|
|
48
|
+
async stats() {
|
|
49
|
+
const version = await this.leakedPasswordService.getCorpusVersion();
|
|
50
|
+
return { count: version.count, lastUpdatedAt: version.lastCreatedAt };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PrismaModule } from '@hed-hog/api-prisma';
|
|
2
|
+
import { forwardRef, Global, Module } from '@nestjs/common';
|
|
3
|
+
import { LeakedPasswordController } from './leaked-password.controller';
|
|
4
|
+
import { LeakedPasswordService } from './leaked-password.service';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `@Global()` porque o validador de política de senha alcança este serviço pelo
|
|
8
|
+
* service locator, de fora da árvore de injeção normal (mesmo caminho do
|
|
9
|
+
* SettingService).
|
|
10
|
+
*/
|
|
11
|
+
@Global()
|
|
12
|
+
@Module({
|
|
13
|
+
imports: [forwardRef(() => PrismaModule)],
|
|
14
|
+
controllers: [LeakedPasswordController],
|
|
15
|
+
providers: [LeakedPasswordService],
|
|
16
|
+
exports: [LeakedPasswordService],
|
|
17
|
+
})
|
|
18
|
+
export class LeakedPasswordModule {}
|