@omnizap-system/omnizap 2.5.12
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/.clusterfuzzlite/Dockerfile +10 -0
- package/.env.example +907 -0
- package/.github/codeql/codeql-config.yml +10 -0
- package/.github/dependabot.yml +35 -0
- package/.github/workflows/ci.yml +73 -0
- package/.github/workflows/codeql.yml +106 -0
- package/.github/workflows/db-migration-check.yml +98 -0
- package/.github/workflows/dependency-review.yml +22 -0
- package/.github/workflows/deploy.yml +95 -0
- package/.github/workflows/release.yml +106 -0
- package/.github/workflows/security-attest-provenance.yml +51 -0
- package/.github/workflows/security-gitleaks.yml +34 -0
- package/.github/workflows/security-runner-hardening.yml +31 -0
- package/.github/workflows/security-scorecard.yml +44 -0
- package/.github/workflows/security-zap-baseline.yml +44 -0
- package/.github/workflows/security-zap-full-scan.yml +43 -0
- package/.github/workflows/security-zizmor.yml +36 -0
- package/.github/workflows/wiki-sync.yml +44 -0
- package/.gitleaks.toml +15 -0
- package/.prettierrc +34 -0
- package/CODE_OF_CONDUCT.md +114 -0
- package/LICENSE +56 -0
- package/README.md +110 -0
- package/SECURITY.md +110 -0
- package/app/config/index.js +4 -0
- package/app/configParts/adminIdentity.js +92 -0
- package/app/configParts/baileysConfig.js +1818 -0
- package/app/configParts/groupUtils.js +692 -0
- package/app/configParts/loggerConfig.js +394 -0
- package/app/configParts/messagePersistenceService.js +305 -0
- package/app/connection/baileysCompatibility.test.js +40 -0
- package/app/connection/baileysDbAuthState.js +344 -0
- package/app/connection/socketController.js +2243 -0
- package/app/controllers/messageController.js +7 -0
- package/app/controllers/messagePipeline/commandMiddleware.js +146 -0
- package/app/controllers/messagePipeline/conversationMiddleware.js +183 -0
- package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +522 -0
- package/app/controllers/messagePipeline/postProcessingMiddleware.js +41 -0
- package/app/controllers/messagePipeline/preProcessingMiddlewares.js +166 -0
- package/app/controllers/messageProcessingPipeline.js +699 -0
- package/app/modules/adminModule/AGENT.md +4056 -0
- package/app/modules/adminModule/adminAiHelpService.js +56 -0
- package/app/modules/adminModule/adminConfigRuntime.js +177 -0
- package/app/modules/adminModule/commandConfig.json +7122 -0
- package/app/modules/adminModule/groupCommandHandlers.js +1823 -0
- package/app/modules/adminModule/groupCommandHandlers.test.js +350 -0
- package/app/modules/adminModule/groupEventHandlers.js +399 -0
- package/app/modules/aiModule/AGENT.md +547 -0
- package/app/modules/aiModule/aiAiHelpService.js +14 -0
- package/app/modules/aiModule/aiConfigRuntime.js +135 -0
- package/app/modules/aiModule/catCommand.js +967 -0
- package/app/modules/aiModule/commandConfig.json +981 -0
- package/app/modules/analyticsModule/messageAnalysisEventRepository.js +83 -0
- package/app/modules/gameModule/AGENT.md +196 -0
- package/app/modules/gameModule/commandConfig.json +366 -0
- package/app/modules/gameModule/diceCommand.js +42 -0
- package/app/modules/gameModule/gameAiHelpService.js +14 -0
- package/app/modules/gameModule/gameConfigRuntime.js +68 -0
- package/app/modules/menuModule/AGENT.md +205 -0
- package/app/modules/menuModule/commandConfig.json +366 -0
- package/app/modules/menuModule/common.js +316 -0
- package/app/modules/menuModule/menuAiHelpService.js +14 -0
- package/app/modules/menuModule/menuConfigRuntime.js +68 -0
- package/app/modules/menuModule/menus.js +66 -0
- package/app/modules/playModule/AGENT.md +321 -0
- package/app/modules/playModule/commandConfig.json +584 -0
- package/app/modules/playModule/playAiHelpService.js +14 -0
- package/app/modules/playModule/playCommand.js +1417 -0
- package/app/modules/playModule/playConfigRuntime.js +68 -0
- package/app/modules/quoteModule/AGENT.md +199 -0
- package/app/modules/quoteModule/commandConfig.json +366 -0
- package/app/modules/quoteModule/quoteAiHelpService.js +14 -0
- package/app/modules/quoteModule/quoteCommand.js +842 -0
- package/app/modules/quoteModule/quoteConfigRuntime.js +68 -0
- package/app/modules/rpgPokemonModule/AGENT.md +229 -0
- package/app/modules/rpgPokemonModule/commandConfig.json +386 -0
- package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +795 -0
- package/app/modules/rpgPokemonModule/rpgBattleService.js +2110 -0
- package/app/modules/rpgPokemonModule/rpgBattleService.test.js +770 -0
- package/app/modules/rpgPokemonModule/rpgEvolutionUtils.js +22 -0
- package/app/modules/rpgPokemonModule/rpgPokemonAiHelpService.js +14 -0
- package/app/modules/rpgPokemonModule/rpgPokemonCommand.js +174 -0
- package/app/modules/rpgPokemonModule/rpgPokemonConfigRuntime.js +68 -0
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +192 -0
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.test.js +93 -0
- package/app/modules/rpgPokemonModule/rpgPokemonEvolution.test.js +46 -0
- package/app/modules/rpgPokemonModule/rpgPokemonMessages.js +746 -0
- package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1847 -0
- package/app/modules/rpgPokemonModule/rpgPokemonService.js +6839 -0
- package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +354 -0
- package/app/modules/statsModule/AGENT.md +320 -0
- package/app/modules/statsModule/commandConfig.json +540 -0
- package/app/modules/statsModule/globalRankingCommand.js +64 -0
- package/app/modules/statsModule/rankingCommand.js +41 -0
- package/app/modules/statsModule/rankingCommon.js +1305 -0
- package/app/modules/statsModule/statsAiHelpService.js +14 -0
- package/app/modules/statsModule/statsConfigRuntime.js +68 -0
- package/app/modules/stickerModule/AGENT.md +692 -0
- package/app/modules/stickerModule/addStickerMetadata.js +239 -0
- package/app/modules/stickerModule/commandConfig.json +1216 -0
- package/app/modules/stickerModule/convertToWebp.js +367 -0
- package/app/modules/stickerModule/stickerAiHelpService.js +14 -0
- package/app/modules/stickerModule/stickerCommand.js +446 -0
- package/app/modules/stickerModule/stickerConfigRuntime.js +68 -0
- package/app/modules/stickerModule/stickerConvertCommand.js +159 -0
- package/app/modules/stickerModule/stickerTextCommand.js +653 -0
- package/app/modules/stickerPackModule/AGENT.md +215 -0
- package/app/modules/stickerPackModule/autoPackCollectorRuntime.js +20 -0
- package/app/modules/stickerPackModule/autoPackCollectorService.js +357 -0
- package/app/modules/stickerPackModule/commandConfig.json +387 -0
- package/app/modules/stickerPackModule/domainEventOutboxRepository.js +227 -0
- package/app/modules/stickerPackModule/domainEvents.js +52 -0
- package/app/modules/stickerPackModule/semanticReclassificationEngine.js +429 -0
- package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +75 -0
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +544 -0
- package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +400 -0
- package/app/modules/stickerPackModule/stickerAssetRepository.js +400 -0
- package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +175 -0
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +3702 -0
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +559 -0
- package/app/modules/stickerPackModule/stickerClassificationService.js +557 -0
- package/app/modules/stickerPackModule/stickerDedicatedTaskWorkerRuntime.js +249 -0
- package/app/modules/stickerPackModule/stickerDomainEventBus.js +65 -0
- package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +208 -0
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +99 -0
- package/app/modules/stickerPackModule/stickerObjectStorageService.js +285 -0
- package/app/modules/stickerPackModule/stickerPackAiHelpService.js +14 -0
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +1148 -0
- package/app/modules/stickerPackModule/stickerPackConfigRuntime.js +68 -0
- package/app/modules/stickerPackModule/stickerPackEngagementRepository.js +152 -0
- package/app/modules/stickerPackModule/stickerPackErrors.js +30 -0
- package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +101 -0
- package/app/modules/stickerPackModule/stickerPackItemRepository.js +432 -0
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +313 -0
- package/app/modules/stickerPackModule/stickerPackMessageService.js +268 -0
- package/app/modules/stickerPackModule/stickerPackRepository.js +450 -0
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRepository.js +179 -0
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +271 -0
- package/app/modules/stickerPackModule/stickerPackService.js +733 -0
- package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +32 -0
- package/app/modules/stickerPackModule/stickerPackUtils.js +107 -0
- package/app/modules/stickerPackModule/stickerStorageService.js +559 -0
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +242 -0
- package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +242 -0
- package/app/modules/systemMetricsModule/AGENT.md +193 -0
- package/app/modules/systemMetricsModule/commandConfig.json +344 -0
- package/app/modules/systemMetricsModule/pingCommand.js +399 -0
- package/app/modules/systemMetricsModule/systemMetricsAiHelpService.js +14 -0
- package/app/modules/systemMetricsModule/systemMetricsConfigRuntime.js +68 -0
- package/app/modules/tiktokModule/AGENT.md +196 -0
- package/app/modules/tiktokModule/commandConfig.json +366 -0
- package/app/modules/tiktokModule/tiktokAiHelpService.js +14 -0
- package/app/modules/tiktokModule/tiktokCommand.js +716 -0
- package/app/modules/tiktokModule/tiktokConfigRuntime.js +68 -0
- package/app/modules/userModule/AGENT.md +200 -0
- package/app/modules/userModule/commandConfig.json +386 -0
- package/app/modules/userModule/userAiHelpService.js +14 -0
- package/app/modules/userModule/userCommand.js +1155 -0
- package/app/modules/userModule/userConfigRuntime.js +68 -0
- package/app/modules/waifuPicsModule/AGENT.md +431 -0
- package/app/modules/waifuPicsModule/commandConfig.json +780 -0
- package/app/modules/waifuPicsModule/waifuPicsAiHelpService.js +14 -0
- package/app/modules/waifuPicsModule/waifuPicsCommand.js +586 -0
- package/app/modules/waifuPicsModule/waifuPicsConfigRuntime.js +68 -0
- package/app/observability/metrics.js +766 -0
- package/app/services/ai/aiHelpResponseCacheRepository.js +280 -0
- package/app/services/ai/aiLearningRepository.js +400 -0
- package/app/services/ai/commandConfigEnrichmentRepository.js +769 -0
- package/app/services/ai/commandConfigEnrichmentService.js +452 -0
- package/app/services/ai/commandConfigValidationService.js +443 -0
- package/app/services/ai/commandToolBuilderService.js +192 -0
- package/app/services/ai/conversationRouterService.js +516 -0
- package/app/services/ai/geminiService.js +115 -0
- package/app/services/ai/geminiService.test.js +87 -0
- package/app/services/ai/globalModuleAiHelpService.js +1412 -0
- package/app/services/ai/globalToolCallingService.js +203 -0
- package/app/services/ai/messageCommandExecutionService.js +391 -0
- package/app/services/ai/moduleAiHelpCoreService.js +1099 -0
- package/app/services/ai/moduleAiHelpWrapperFactory.js +65 -0
- package/app/services/ai/moduleCommandConfigRuntimeService.js +113 -0
- package/app/services/ai/moduleToolExecutorService.js +464 -0
- package/app/services/ai/moduleToolRegistryService.js +178 -0
- package/app/services/ai/toolCandidateSelectorService.js +781 -0
- package/app/services/auth/googleWebLinkService.js +80 -0
- package/app/services/auth/whatsappLoginLinkService.js +230 -0
- package/app/services/external/pokeApiService.js +398 -0
- package/app/services/group/groupMetadataService.js +311 -0
- package/app/services/infra/dbWriteQueue.js +874 -0
- package/app/services/infra/featureFlagService.js +131 -0
- package/app/services/infra/queueUtils.js +55 -0
- package/app/services/messaging/captchaService.js +491 -0
- package/app/services/messaging/messagePersistenceService.js +1 -0
- package/app/services/messaging/newsBroadcastService.js +347 -0
- package/app/services/sticker/stickerFocusService.js +347 -0
- package/app/services/sticker/stickerFocusService.test.js +43 -0
- package/app/store/aiPromptStore.js +38 -0
- package/app/store/conversationSessionStore.js +131 -0
- package/app/store/groupConfigStore.js +58 -0
- package/app/store/premiumUserStore.js +54 -0
- package/app/utils/antiLink/antiLinkModule.js +700 -0
- package/app/utils/http/getImageBufferModule.js +18 -0
- package/app/utils/json/jsonSanitizer.js +113 -0
- package/app/utils/json/jsonSanitizer.test.js +40 -0
- package/app/utils/systemMetrics/systemMetricsModule.js +88 -0
- package/app/workers/aiLearningWorker.js +605 -0
- package/app/workers/commandConfigEnrichmentWorker.js +242 -0
- package/database/index.js +2075 -0
- package/database/init.js +151 -0
- package/database/migrations/.gitkeep +0 -0
- package/database/migrations/20260307_d0_hardening_down.sql +64 -0
- package/database/migrations/20260307_d0_hardening_up.sql +79 -0
- package/database/migrations/20260307_d1_terms_acceptance_down.sql +11 -0
- package/database/migrations/20260307_d1_terms_acceptance_up.sql +37 -0
- package/database/migrations/20260307_d2_auth_hardening_down.sql +75 -0
- package/database/migrations/20260307_d2_auth_hardening_up.sql +100 -0
- package/database/migrations/20260314_d7_canonical_sender_down.sql +53 -0
- package/database/migrations/20260314_d7_canonical_sender_up.sql +114 -0
- package/database/migrations/20260406_d30_security_analytics_down.sql +95 -0
- package/database/migrations/20260406_d30_security_analytics_up.sql +292 -0
- package/database/migrations/20260407_d31_web_google_session_token_hardening_down.sql +2 -0
- package/database/migrations/20260407_d31_web_google_session_token_hardening_up.sql +17 -0
- package/database/migrations/20260408_d32_ai_help_response_cache_down.sql +1 -0
- package/database/migrations/20260408_d32_ai_help_response_cache_up.sql +22 -0
- package/database/migrations/20260409_d33_ai_learning_tables_down.sql +4 -0
- package/database/migrations/20260409_d33_ai_learning_tables_up.sql +52 -0
- package/database/migrations/20260410_d34_command_config_enrichment_down.sql +3 -0
- package/database/migrations/20260410_d34_command_config_enrichment_up.sql +48 -0
- package/database/schema.sql +1186 -0
- package/docker-compose.yml +104 -0
- package/docs/audits/stickerCatalogController-out-of-scope.md +103 -0
- package/docs/audits/stickerCatalogController-symbols.md +58 -0
- package/docs/compliance/acceptable-use-policy-2026-03-07.md +35 -0
- package/docs/compliance/dpa-b2b-standard-2026-03-07.md +80 -0
- package/docs/compliance/monthly-compliance-checklist-2026-03-07.md +88 -0
- package/docs/compliance/notice-and-takedown-policy-2026-03-07.md +34 -0
- package/docs/compliance/privacy-policy-2026-03-07.md +75 -0
- package/docs/compliance/subprocessors-inventory-2026-03-07.md +16 -0
- package/docs/database/production-db-evolution-runbook-2026q1.md +365 -0
- package/docs/security/dsar-lgpd-runbook-2026-03-07.md +86 -0
- package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +77 -0
- package/docs/security/network-hardening-runbook-2026-03-07.md +137 -0
- package/docs/seo/omnizap-seo-playbook-br-2026-02-28.md +238 -0
- package/docs/seo/satellite-page-template.md +116 -0
- package/docs/seo/satellite-pages-phase1.json +364 -0
- package/docs/wiki/Home.md +120 -0
- package/docs/wiki/pair-extraordinaire-2026-03-08.md +3 -0
- package/docs/wiki/recent-changes-2026-03-08.md +47 -0
- package/ecosystem.prod.config.cjs +135 -0
- package/eslint.config.js +89 -0
- package/index.js +488 -0
- package/ml/clip_classifier/Dockerfile +18 -0
- package/ml/clip_classifier/README.md +118 -0
- package/ml/clip_classifier/adaptive_scoring.py +40 -0
- package/ml/clip_classifier/classifier.py +654 -0
- package/ml/clip_classifier/embedding_store.py +481 -0
- package/ml/clip_classifier/env_loader.py +15 -0
- package/ml/clip_classifier/llm_label_expander.py +144 -0
- package/ml/clip_classifier/main.py +213 -0
- package/ml/clip_classifier/requirements.txt +10 -0
- package/ml/clip_classifier/similarity_engine.py +74 -0
- package/new-logo.png +0 -0
- package/observability/alert-rules.yml +60 -0
- package/observability/grafana/dashboards/omnizap-mysql.json +136 -0
- package/observability/grafana/dashboards/omnizap-overview.json +170 -0
- package/observability/grafana/provisioning/dashboards/dashboards.yml +11 -0
- package/observability/grafana/provisioning/datasources/datasources.yml +15 -0
- package/observability/loki-config.yml +38 -0
- package/observability/mysql-setup.sql +46 -0
- package/observability/prometheus.yml +35 -0
- package/observability/promtail-config.yml +84 -0
- package/observability/sticker-catalog-slo.md +83 -0
- package/observability/sticker-scale-hardening-rollout.md +128 -0
- package/package.json +144 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/assets/css/commands-react.input.css +71 -0
- package/public/assets/css/create-pack-react.input.css +31 -0
- package/public/assets/css/home-react.input.css +106 -0
- package/public/assets/css/login-react.input.css +58 -0
- package/public/assets/css/stickers-react.input.css +18 -0
- package/public/assets/css/terms-react.input.css +115 -0
- package/public/assets/css/user-react.input.css +57 -0
- package/public/assets/images/brand-icon-192.png +0 -0
- package/public/assets/images/brand-logo-128.webp +0 -0
- package/public/assets/images/hero-banner-1280.jpg +0 -0
- package/public/comandos/commands-catalog.json +4517 -0
- package/public/css/api-docs.css +161 -0
- package/public/css/stickers-admin.css +1288 -0
- package/public/css/styles.css +679 -0
- package/public/css/systemadm/admin.css +474 -0
- package/public/css/systemadm/base.css +73 -0
- package/public/css/systemadm/components.css +662 -0
- package/public/css/systemadm/layout.css +229 -0
- package/public/css/systemadm/tokens.css +56 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/js/apps/apiDocsApp.js +235 -0
- package/public/js/apps/commandsReactApp.js +528 -0
- package/public/js/apps/createPackApp.js +1646 -0
- package/public/js/apps/homeReactApp.js +942 -0
- package/public/js/apps/loginReactApp.js +496 -0
- package/public/js/apps/stickersAdminApp.js +1753 -0
- package/public/js/apps/stickersApp.js +3797 -0
- package/public/js/apps/termsReactApp.js +528 -0
- package/public/js/apps/userApp.js +2540 -0
- package/public/js/apps/userProfile/actions.js +66 -0
- package/public/js/apps/userReactApp.js +547 -0
- package/public/js/catalog.js +950 -0
- package/public/pages/api-docs.html +40 -0
- package/public/pages/aup.html +158 -0
- package/public/pages/comandos.html +41 -0
- package/public/pages/dpa.html +227 -0
- package/public/pages/home.html +45 -0
- package/public/pages/licenca.html +182 -0
- package/public/pages/login.html +40 -0
- package/public/pages/notice-and-takedown.html +234 -0
- package/public/pages/politica-de-privacidade.html +251 -0
- package/public/pages/seo-bot-whatsapp-para-grupo.html +350 -0
- package/public/pages/seo-bot-whatsapp-sem-programar.html +350 -0
- package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +350 -0
- package/public/pages/seo-como-criar-comandos-whatsapp.html +350 -0
- package/public/pages/seo-como-evitar-spam-no-whatsapp.html +350 -0
- package/public/pages/seo-como-moderar-grupo-whatsapp.html +350 -0
- package/public/pages/seo-como-organizar-comunidade-whatsapp.html +350 -0
- package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +350 -0
- package/public/pages/stickers-admin.html +31 -0
- package/public/pages/stickers-create.html +41 -0
- package/public/pages/stickers.html +45 -0
- package/public/pages/suboperadores.html +237 -0
- package/public/pages/termos-de-uso-texto-integral.html +241 -0
- package/public/pages/termos-de-uso.html +41 -0
- package/public/pages/user-password-reset.html +32 -0
- package/public/pages/user-systemadm.html +508 -0
- package/public/pages/user.html +39 -0
- package/public/robots.txt +9 -0
- package/public/site.webmanifest +24 -0
- package/public/sitemap.xml +98 -0
- package/schemas/command-config.schema.json +582 -0
- package/scripts/baileys-compat-smoke.mjs +12 -0
- package/scripts/cache-bust.mjs +142 -0
- package/scripts/deploy.sh +916 -0
- package/scripts/email-broadcast-terms-update.mjs +170 -0
- package/scripts/enrich-command-discovery-fields.mjs +286 -0
- package/scripts/generate-command-config-schema.mjs +273 -0
- package/scripts/generate-commands-catalog.mjs +308 -0
- package/scripts/generate-module-agents.mjs +631 -0
- package/scripts/generate-seo-satellite-pages.mjs +400 -0
- package/scripts/github-deploy-notify.mjs +174 -0
- package/scripts/github-release-notify.mjs +219 -0
- package/scripts/release.sh +599 -0
- package/scripts/run-codeql-local.sh +116 -0
- package/scripts/run-prettier-all.mjs +25 -0
- package/scripts/security-smoketest.mjs +581 -0
- package/scripts/sticker-catalog-loadtest.mjs +210 -0
- package/scripts/sticker-worker-task.mjs +119 -0
- package/scripts/sync-readme-snapshot.mjs +133 -0
- package/scripts/validate-command-config-schema.mjs +130 -0
- package/scripts/validate-command-configs.mjs +15 -0
- package/scripts/wiki-sync.sh +191 -0
- package/server/auth/googleWebAuth/googleWebAuthRuntime.js +62 -0
- package/server/auth/googleWebAuth/googleWebAuthService.js +807 -0
- package/server/auth/jwt/webJwtService.js +147 -0
- package/server/auth/stickerCatalogAuthContext.js +165 -0
- package/server/auth/termsAcceptance/termsAcceptanceHandler.js +189 -0
- package/server/auth/userPassword/index.js +14 -0
- package/server/auth/userPassword/userPasswordAuthService.js +422 -0
- package/server/auth/userPassword/userPasswordCrypto.js +199 -0
- package/server/auth/userPassword/userPasswordCrypto.test.js +76 -0
- package/server/auth/userPassword/userPasswordRecoveryService.js +728 -0
- package/server/auth/validation/authSchemas.js +236 -0
- package/server/auth/webAccount/webAccountHandlers.js +1434 -0
- package/server/controllers/admin/adminBanService.js +138 -0
- package/server/controllers/admin/adminPanelHandlers.js +2083 -0
- package/server/controllers/admin/stickerCatalogAdminContext.js +17 -0
- package/server/controllers/admin/systemAdminController.js +201 -0
- package/server/controllers/email/emailAutomationController.js +239 -0
- package/server/controllers/metricsController.js +21 -0
- package/server/controllers/seo/stickerCatalogSeoContext.js +514 -0
- package/server/controllers/sticker/nonCatalogHandlers.js +303 -0
- package/server/controllers/sticker/stickerCatalogController.js +4700 -0
- package/server/controllers/system/contactController.js +115 -0
- package/server/controllers/system/githubController.js +137 -0
- package/server/controllers/system/stickerCatalogSystemContext.js +758 -0
- package/server/controllers/system/storageController.js +154 -0
- package/server/controllers/system/systemController.js +135 -0
- package/server/controllers/system/systemMetricsController.js +156 -0
- package/server/controllers/system/visitController.js +90 -0
- package/server/controllers/userController.js +145 -0
- package/server/email/emailAutomationRuntime.js +225 -0
- package/server/email/emailAutomationService.js +125 -0
- package/server/email/emailOutboxRepository.js +282 -0
- package/server/email/emailTemplateService.js +480 -0
- package/server/email/emailTransportService.js +156 -0
- package/server/http/clientIp.js +95 -0
- package/server/http/httpRequestUtils.js +262 -0
- package/server/http/httpRequestUtils.test.js +80 -0
- package/server/http/httpServer.js +180 -0
- package/server/http/requestContext.js +20 -0
- package/server/http/siteRoutingUtils.js +87 -0
- package/server/index.js +1 -0
- package/server/middleware/cachePolicy.js +26 -0
- package/server/middleware/cachePolicyHelpers.js +1 -0
- package/server/middleware/endpointRateLimit.js +181 -0
- package/server/middleware/rateLimit.js +70 -0
- package/server/middleware/requireAdminAuth.js +48 -0
- package/server/middleware/securityHeaders.js +97 -0
- package/server/routes/admin/systemAdminRouter.js +64 -0
- package/server/routes/email/emailAutomationRouter.js +46 -0
- package/server/routes/health/healthRouter.js +41 -0
- package/server/routes/indexRouter.js +234 -0
- package/server/routes/metrics/metricsRouter.js +58 -0
- package/server/routes/static/staticPageRouter.js +134 -0
- package/server/routes/sticker/catalogHandlers/catalogAdminHttp.js +105 -0
- package/server/routes/sticker/catalogHandlers/catalogAuthHttp.js +77 -0
- package/server/routes/sticker/catalogHandlers/catalogPublicHttp.js +120 -0
- package/server/routes/sticker/catalogHandlers/catalogUploadHttp.js +83 -0
- package/server/routes/sticker/catalogRouter.js +77 -0
- package/server/routes/sticker/stickerApiRouter.js +84 -0
- package/server/routes/sticker/stickerDataRouter.js +145 -0
- package/server/routes/sticker/stickerSiteRouter.js +43 -0
- package/server/routes/user/userApiPaths.js +66 -0
- package/server/routes/user/userRouter.js +65 -0
- package/server/utils/safePath.js +26 -0
- package/utils/logger/loggerModule.js +35 -0
- package/vite.config.mjs +38 -0
package/database/init.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import mysql from 'mysql2/promise';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
import logger from '#logger';
|
|
7
|
+
import { dbConfig } from './index.js';
|
|
8
|
+
|
|
9
|
+
const dbToCreate = dbConfig.database;
|
|
10
|
+
|
|
11
|
+
const createDatabaseSQL = `
|
|
12
|
+
CREATE DATABASE IF NOT EXISTS \`${dbToCreate}\`
|
|
13
|
+
DEFAULT CHARACTER SET utf8mb4
|
|
14
|
+
DEFAULT COLLATE utf8mb4_unicode_ci;
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
18
|
+
const __dirname = path.dirname(__filename);
|
|
19
|
+
const SCHEMA_SQL_PATH = path.join(__dirname, 'schema.sql');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Divide um arquivo SQL em statements individuais.
|
|
23
|
+
* Suporta aspas simples e duplas para não quebrar strings.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} sql
|
|
26
|
+
* @returns {string[]}
|
|
27
|
+
*/
|
|
28
|
+
function splitSqlStatements(sql) {
|
|
29
|
+
const statements = [];
|
|
30
|
+
let current = '';
|
|
31
|
+
let inSingleQuote = false;
|
|
32
|
+
let inDoubleQuote = false;
|
|
33
|
+
let escaped = false;
|
|
34
|
+
|
|
35
|
+
for (const char of sql) {
|
|
36
|
+
if (escaped) {
|
|
37
|
+
current += char;
|
|
38
|
+
escaped = false;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (char === '\\') {
|
|
43
|
+
current += char;
|
|
44
|
+
escaped = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (char === "'" && !inDoubleQuote) {
|
|
49
|
+
inSingleQuote = !inSingleQuote;
|
|
50
|
+
current += char;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (char === '"' && !inSingleQuote) {
|
|
55
|
+
inDoubleQuote = !inDoubleQuote;
|
|
56
|
+
current += char;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (char === ';' && !inSingleQuote && !inDoubleQuote) {
|
|
61
|
+
const statement = current.trim();
|
|
62
|
+
if (statement) statements.push(statement);
|
|
63
|
+
current = '';
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
current += char;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const trailing = current.trim();
|
|
71
|
+
if (trailing) statements.push(trailing);
|
|
72
|
+
|
|
73
|
+
return statements;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Executa o schema consolidado para garantir que todas as tabelas existam.
|
|
78
|
+
*
|
|
79
|
+
* @param {import('mysql2/promise').Connection} connection
|
|
80
|
+
* @returns {Promise<number>} Quantidade de statements executados.
|
|
81
|
+
*/
|
|
82
|
+
async function runSchemaBootstrap(connection) {
|
|
83
|
+
let sqlContent = '';
|
|
84
|
+
try {
|
|
85
|
+
sqlContent = await fs.readFile(SCHEMA_SQL_PATH, 'utf8');
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (error?.code === 'ENOENT') {
|
|
88
|
+
const wrapped = new Error(`Arquivo de schema não encontrado em ${SCHEMA_SQL_PATH}.`);
|
|
89
|
+
wrapped.code = 'SCHEMA_SQL_NOT_FOUND';
|
|
90
|
+
throw wrapped;
|
|
91
|
+
}
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const statements = splitSqlStatements(sqlContent);
|
|
96
|
+
if (statements.length === 0) {
|
|
97
|
+
logger.warn('Arquivo schema.sql está vazio. Nenhuma tabela será criada.');
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const statement of statements) {
|
|
102
|
+
await connection.query(statement);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return statements.length;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Inicializa o banco de dados:
|
|
110
|
+
* 1) Conecta ao MySQL sem database
|
|
111
|
+
* 2) Cria o banco se não existir
|
|
112
|
+
* 3) Muda para o database correto
|
|
113
|
+
* 4) Executa o schema consolidado (sem migrations)
|
|
114
|
+
* 5) Encerra a conexão
|
|
115
|
+
*
|
|
116
|
+
* @returns {Promise<void>}
|
|
117
|
+
*/
|
|
118
|
+
export default async function initializeDatabase() {
|
|
119
|
+
let connection;
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
connection = await mysql.createConnection({
|
|
123
|
+
host: dbConfig.host,
|
|
124
|
+
user: dbConfig.user,
|
|
125
|
+
password: dbConfig.password,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await connection.query(createDatabaseSQL);
|
|
129
|
+
logger.info(`Banco de dados '${dbToCreate}' verificado/criado com sucesso.`);
|
|
130
|
+
|
|
131
|
+
await connection.changeUser({ database: dbToCreate });
|
|
132
|
+
|
|
133
|
+
const executedStatements = await runSchemaBootstrap(connection);
|
|
134
|
+
|
|
135
|
+
logger.info('Schema consolidado verificado/aplicado com sucesso (sem migrations).', {
|
|
136
|
+
executedStatements,
|
|
137
|
+
});
|
|
138
|
+
} catch (error) {
|
|
139
|
+
logger.error(`Erro ao inicializar o banco: ${error.code || ''} ${error.message}`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
} finally {
|
|
142
|
+
if (connection) {
|
|
143
|
+
await connection.end();
|
|
144
|
+
logger.info('Conexão com o MySQL encerrada após inicialização.');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (process.argv[1] === __filename) {
|
|
150
|
+
initializeDatabase();
|
|
151
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
-- D0 rollback
|
|
2
|
+
-- Run with mysql client:
|
|
3
|
+
-- mysql -u$DB_USER -p$DB_PASSWORD -h$DB_HOST $DB_NAME < database/migrations/20260307_d0_hardening_down.sql
|
|
4
|
+
|
|
5
|
+
SET @migration_key := '20260307_d0_hardening';
|
|
6
|
+
|
|
7
|
+
DROP PROCEDURE IF EXISTS __ensure_index;
|
|
8
|
+
DROP PROCEDURE IF EXISTS __drop_index_if_exists;
|
|
9
|
+
|
|
10
|
+
DELIMITER $$
|
|
11
|
+
CREATE PROCEDURE __ensure_index(IN p_table_name VARCHAR(64), IN p_index_name VARCHAR(64), IN p_ddl TEXT)
|
|
12
|
+
BEGIN
|
|
13
|
+
IF NOT EXISTS (
|
|
14
|
+
SELECT 1
|
|
15
|
+
FROM information_schema.statistics
|
|
16
|
+
WHERE table_schema = DATABASE()
|
|
17
|
+
AND table_name = p_table_name
|
|
18
|
+
AND index_name = p_index_name
|
|
19
|
+
) THEN
|
|
20
|
+
SET @ddl = p_ddl;
|
|
21
|
+
PREPARE stmt FROM @ddl;
|
|
22
|
+
EXECUTE stmt;
|
|
23
|
+
DEALLOCATE PREPARE stmt;
|
|
24
|
+
END IF;
|
|
25
|
+
END$$
|
|
26
|
+
|
|
27
|
+
CREATE PROCEDURE __drop_index_if_exists(IN p_table_name VARCHAR(64), IN p_index_name VARCHAR(64))
|
|
28
|
+
BEGIN
|
|
29
|
+
IF EXISTS (
|
|
30
|
+
SELECT 1
|
|
31
|
+
FROM information_schema.statistics
|
|
32
|
+
WHERE table_schema = DATABASE()
|
|
33
|
+
AND table_name = p_table_name
|
|
34
|
+
AND index_name = p_index_name
|
|
35
|
+
) THEN
|
|
36
|
+
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` DROP INDEX `', p_index_name, '`');
|
|
37
|
+
PREPARE stmt FROM @ddl;
|
|
38
|
+
EXECUTE stmt;
|
|
39
|
+
DEALLOCATE PREPARE stmt;
|
|
40
|
+
END IF;
|
|
41
|
+
END$$
|
|
42
|
+
DELIMITER ;
|
|
43
|
+
|
|
44
|
+
-- Restore redundant indexes removed in D0
|
|
45
|
+
CALL __ensure_index('sticker_pack_item', 'idx_sticker_pack_item_pack_position', 'CREATE INDEX idx_sticker_pack_item_pack_position ON sticker_pack_item (pack_id, position)');
|
|
46
|
+
CALL __ensure_index('domain_event_outbox_dlq', 'idx_domain_event_outbox_dlq_outbox_event_id', 'CREATE INDEX idx_domain_event_outbox_dlq_outbox_event_id ON domain_event_outbox_dlq (outbox_event_id)');
|
|
47
|
+
CALL __ensure_index('sticker_worker_task_dlq', 'idx_sticker_worker_task_dlq_task_id', 'CREATE INDEX idx_sticker_worker_task_dlq_task_id ON sticker_worker_task_dlq (task_id)');
|
|
48
|
+
|
|
49
|
+
-- Drop indexes added in D0
|
|
50
|
+
CALL __drop_index_if_exists('messages', 'idx_messages_sender_timestamp');
|
|
51
|
+
CALL __drop_index_if_exists('messages', 'idx_messages_chat_sender_timestamp');
|
|
52
|
+
CALL __drop_index_if_exists('domain_event_outbox', 'idx_domain_event_outbox_status_locked');
|
|
53
|
+
CALL __drop_index_if_exists('email_outbox', 'idx_email_outbox_status_locked');
|
|
54
|
+
CALL __drop_index_if_exists('sticker_worker_task_queue', 'idx_sticker_worker_task_queue_status_locked');
|
|
55
|
+
CALL __drop_index_if_exists('sticker_asset_reprocess_queue', 'idx_sticker_asset_reprocess_queue_status_locked');
|
|
56
|
+
|
|
57
|
+
UPDATE schema_change_log
|
|
58
|
+
SET status = 'rolled_back',
|
|
59
|
+
notes = 'D0 rollback executed',
|
|
60
|
+
updated_at = CURRENT_TIMESTAMP
|
|
61
|
+
WHERE migration_key = @migration_key;
|
|
62
|
+
|
|
63
|
+
DROP PROCEDURE IF EXISTS __ensure_index;
|
|
64
|
+
DROP PROCEDURE IF EXISTS __drop_index_if_exists;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
-- D0 (2026-03-07) - Non-breaking hardening
|
|
2
|
+
-- Scope: indexes for queue reclaim/perf, remove redundant indexes, migration audit table
|
|
3
|
+
-- Run with mysql client:
|
|
4
|
+
-- mysql -u$DB_USER -p$DB_PASSWORD -h$DB_HOST $DB_NAME < database/migrations/20260307_d0_hardening_up.sql
|
|
5
|
+
|
|
6
|
+
SET @migration_key := '20260307_d0_hardening';
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS schema_change_log (
|
|
9
|
+
migration_key VARCHAR(128) NOT NULL,
|
|
10
|
+
phase VARCHAR(32) NOT NULL,
|
|
11
|
+
status ENUM('applied', 'rolled_back') NOT NULL DEFAULT 'applied',
|
|
12
|
+
notes VARCHAR(255) DEFAULT NULL,
|
|
13
|
+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
14
|
+
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
15
|
+
PRIMARY KEY (migration_key),
|
|
16
|
+
KEY idx_schema_change_log_phase_status (phase, status, updated_at)
|
|
17
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
18
|
+
|
|
19
|
+
DROP PROCEDURE IF EXISTS __ensure_index;
|
|
20
|
+
DROP PROCEDURE IF EXISTS __drop_index_if_exists;
|
|
21
|
+
|
|
22
|
+
DELIMITER $$
|
|
23
|
+
CREATE PROCEDURE __ensure_index(IN p_table_name VARCHAR(64), IN p_index_name VARCHAR(64), IN p_ddl TEXT)
|
|
24
|
+
BEGIN
|
|
25
|
+
IF NOT EXISTS (
|
|
26
|
+
SELECT 1
|
|
27
|
+
FROM information_schema.statistics
|
|
28
|
+
WHERE table_schema = DATABASE()
|
|
29
|
+
AND table_name = p_table_name
|
|
30
|
+
AND index_name = p_index_name
|
|
31
|
+
) THEN
|
|
32
|
+
SET @ddl = p_ddl;
|
|
33
|
+
PREPARE stmt FROM @ddl;
|
|
34
|
+
EXECUTE stmt;
|
|
35
|
+
DEALLOCATE PREPARE stmt;
|
|
36
|
+
END IF;
|
|
37
|
+
END$$
|
|
38
|
+
|
|
39
|
+
CREATE PROCEDURE __drop_index_if_exists(IN p_table_name VARCHAR(64), IN p_index_name VARCHAR(64))
|
|
40
|
+
BEGIN
|
|
41
|
+
IF EXISTS (
|
|
42
|
+
SELECT 1
|
|
43
|
+
FROM information_schema.statistics
|
|
44
|
+
WHERE table_schema = DATABASE()
|
|
45
|
+
AND table_name = p_table_name
|
|
46
|
+
AND index_name = p_index_name
|
|
47
|
+
) THEN
|
|
48
|
+
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` DROP INDEX `', p_index_name, '`');
|
|
49
|
+
PREPARE stmt FROM @ddl;
|
|
50
|
+
EXECUTE stmt;
|
|
51
|
+
DEALLOCATE PREPARE stmt;
|
|
52
|
+
END IF;
|
|
53
|
+
END$$
|
|
54
|
+
DELIMITER ;
|
|
55
|
+
|
|
56
|
+
-- Performance indexes (non-breaking)
|
|
57
|
+
CALL __ensure_index('messages', 'idx_messages_sender_timestamp', 'CREATE INDEX idx_messages_sender_timestamp ON messages (sender_id, timestamp)');
|
|
58
|
+
CALL __ensure_index('messages', 'idx_messages_chat_sender_timestamp', 'CREATE INDEX idx_messages_chat_sender_timestamp ON messages (chat_id, sender_id, timestamp)');
|
|
59
|
+
|
|
60
|
+
CALL __ensure_index('domain_event_outbox', 'idx_domain_event_outbox_status_locked', 'CREATE INDEX idx_domain_event_outbox_status_locked ON domain_event_outbox (status, locked_at)');
|
|
61
|
+
CALL __ensure_index('email_outbox', 'idx_email_outbox_status_locked', 'CREATE INDEX idx_email_outbox_status_locked ON email_outbox (status, locked_at)');
|
|
62
|
+
CALL __ensure_index('sticker_worker_task_queue', 'idx_sticker_worker_task_queue_status_locked', 'CREATE INDEX idx_sticker_worker_task_queue_status_locked ON sticker_worker_task_queue (status, locked_at)');
|
|
63
|
+
CALL __ensure_index('sticker_asset_reprocess_queue', 'idx_sticker_asset_reprocess_queue_status_locked', 'CREATE INDEX idx_sticker_asset_reprocess_queue_status_locked ON sticker_asset_reprocess_queue (status, locked_at)');
|
|
64
|
+
|
|
65
|
+
-- Remove redundant indexes (safe)
|
|
66
|
+
CALL __drop_index_if_exists('sticker_pack_item', 'idx_sticker_pack_item_pack_position');
|
|
67
|
+
CALL __drop_index_if_exists('domain_event_outbox_dlq', 'idx_domain_event_outbox_dlq_outbox_event_id');
|
|
68
|
+
CALL __drop_index_if_exists('sticker_worker_task_dlq', 'idx_sticker_worker_task_dlq_task_id');
|
|
69
|
+
|
|
70
|
+
INSERT INTO schema_change_log (migration_key, phase, status, notes)
|
|
71
|
+
VALUES (@migration_key, 'D0', 'applied', 'Indexes hardening + redundant index cleanup')
|
|
72
|
+
ON DUPLICATE KEY UPDATE
|
|
73
|
+
phase = VALUES(phase),
|
|
74
|
+
status = 'applied',
|
|
75
|
+
notes = VALUES(notes),
|
|
76
|
+
updated_at = CURRENT_TIMESTAMP;
|
|
77
|
+
|
|
78
|
+
DROP PROCEDURE IF EXISTS __ensure_index;
|
|
79
|
+
DROP PROCEDURE IF EXISTS __drop_index_if_exists;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- D1 rollback
|
|
2
|
+
|
|
3
|
+
SET @migration_key := '20260307_d1_terms_acceptance';
|
|
4
|
+
|
|
5
|
+
DROP TABLE IF EXISTS web_terms_acceptance_event;
|
|
6
|
+
|
|
7
|
+
UPDATE schema_change_log
|
|
8
|
+
SET status = 'rolled_back',
|
|
9
|
+
notes = 'D1 rollback executado',
|
|
10
|
+
updated_at = CURRENT_TIMESTAMP
|
|
11
|
+
WHERE migration_key = @migration_key;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
-- D1 (2026-03-07) - Registro versionado de aceite juridico
|
|
2
|
+
-- Scope: trilha probatoria de aceite de Termos/Politicas (hash da versao + timestamp + IP + user agent)
|
|
3
|
+
|
|
4
|
+
SET @migration_key := '20260307_d1_terms_acceptance';
|
|
5
|
+
|
|
6
|
+
CREATE TABLE IF NOT EXISTS web_terms_acceptance_event (
|
|
7
|
+
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
8
|
+
event_id CHAR(36) NOT NULL,
|
|
9
|
+
document_key VARCHAR(64) NOT NULL,
|
|
10
|
+
document_version VARCHAR(64) NOT NULL,
|
|
11
|
+
document_version_hash CHAR(64) NOT NULL,
|
|
12
|
+
accepted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
13
|
+
accepted_at_client TIMESTAMP NULL DEFAULT NULL,
|
|
14
|
+
source VARCHAR(32) NOT NULL DEFAULT 'web_login',
|
|
15
|
+
google_sub VARCHAR(80) DEFAULT NULL,
|
|
16
|
+
email VARCHAR(255) DEFAULT NULL,
|
|
17
|
+
owner_jid VARCHAR(120) DEFAULT NULL,
|
|
18
|
+
session_key VARCHAR(80) DEFAULT NULL,
|
|
19
|
+
ip_address VARCHAR(64) DEFAULT NULL,
|
|
20
|
+
user_agent VARCHAR(512) DEFAULT NULL,
|
|
21
|
+
metadata LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(metadata)),
|
|
22
|
+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
23
|
+
PRIMARY KEY (id),
|
|
24
|
+
UNIQUE KEY uq_web_terms_acceptance_event_id (event_id),
|
|
25
|
+
KEY idx_web_terms_acceptance_doc_version (document_key, document_version, accepted_at),
|
|
26
|
+
KEY idx_web_terms_acceptance_identity (google_sub, email, owner_jid, accepted_at),
|
|
27
|
+
KEY idx_web_terms_acceptance_source_created (source, created_at),
|
|
28
|
+
KEY idx_web_terms_acceptance_session_created (session_key, created_at)
|
|
29
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
30
|
+
|
|
31
|
+
INSERT INTO schema_change_log (migration_key, phase, status, notes)
|
|
32
|
+
VALUES (@migration_key, 'D1', 'applied', 'Tabela de aceite versionado de termos/politicas')
|
|
33
|
+
ON DUPLICATE KEY UPDATE
|
|
34
|
+
phase = VALUES(phase),
|
|
35
|
+
status = 'applied',
|
|
36
|
+
notes = VALUES(notes),
|
|
37
|
+
updated_at = CURRENT_TIMESTAMP;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
-- D2 rollback
|
|
2
|
+
|
|
3
|
+
SET @migration_key := '20260307_d2_auth_hardening';
|
|
4
|
+
|
|
5
|
+
DROP PROCEDURE IF EXISTS __drop_column_if_exists;
|
|
6
|
+
DROP PROCEDURE IF EXISTS __drop_index_if_exists;
|
|
7
|
+
|
|
8
|
+
DELIMITER $$
|
|
9
|
+
CREATE PROCEDURE __drop_column_if_exists(IN p_table_name VARCHAR(64), IN p_column_name VARCHAR(64), IN p_ddl TEXT)
|
|
10
|
+
BEGIN
|
|
11
|
+
IF EXISTS (
|
|
12
|
+
SELECT 1
|
|
13
|
+
FROM information_schema.columns
|
|
14
|
+
WHERE table_schema = DATABASE()
|
|
15
|
+
AND table_name = p_table_name
|
|
16
|
+
AND column_name = p_column_name
|
|
17
|
+
) THEN
|
|
18
|
+
SET @ddl = p_ddl;
|
|
19
|
+
PREPARE stmt FROM @ddl;
|
|
20
|
+
EXECUTE stmt;
|
|
21
|
+
DEALLOCATE PREPARE stmt;
|
|
22
|
+
END IF;
|
|
23
|
+
END$$
|
|
24
|
+
|
|
25
|
+
CREATE PROCEDURE __drop_index_if_exists(IN p_table_name VARCHAR(64), IN p_index_name VARCHAR(64), IN p_ddl TEXT)
|
|
26
|
+
BEGIN
|
|
27
|
+
IF EXISTS (
|
|
28
|
+
SELECT 1
|
|
29
|
+
FROM information_schema.statistics
|
|
30
|
+
WHERE table_schema = DATABASE()
|
|
31
|
+
AND table_name = p_table_name
|
|
32
|
+
AND index_name = p_index_name
|
|
33
|
+
) THEN
|
|
34
|
+
SET @ddl = p_ddl;
|
|
35
|
+
PREPARE stmt FROM @ddl;
|
|
36
|
+
EXECUTE stmt;
|
|
37
|
+
DEALLOCATE PREPARE stmt;
|
|
38
|
+
END IF;
|
|
39
|
+
END$$
|
|
40
|
+
DELIMITER ;
|
|
41
|
+
|
|
42
|
+
CALL __drop_index_if_exists(
|
|
43
|
+
'web_user_password_recovery_code',
|
|
44
|
+
'idx_web_user_password_recovery_email_hash_created',
|
|
45
|
+
'DROP INDEX idx_web_user_password_recovery_email_hash_created ON web_user_password_recovery_code'
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
CALL __drop_column_if_exists(
|
|
49
|
+
'web_user_password_recovery_code',
|
|
50
|
+
'email_hash',
|
|
51
|
+
'ALTER TABLE web_user_password_recovery_code DROP COLUMN email_hash'
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
CALL __drop_column_if_exists(
|
|
55
|
+
'web_user_password_recovery_code',
|
|
56
|
+
'requested_ip_hash',
|
|
57
|
+
'ALTER TABLE web_user_password_recovery_code DROP COLUMN requested_ip_hash'
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CALL __drop_column_if_exists(
|
|
61
|
+
'web_user_password_recovery_code',
|
|
62
|
+
'requested_user_agent_hash',
|
|
63
|
+
'ALTER TABLE web_user_password_recovery_code DROP COLUMN requested_user_agent_hash'
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
DROP TABLE IF EXISTS web_user_password_login_throttle;
|
|
67
|
+
|
|
68
|
+
DROP PROCEDURE IF EXISTS __drop_column_if_exists;
|
|
69
|
+
DROP PROCEDURE IF EXISTS __drop_index_if_exists;
|
|
70
|
+
|
|
71
|
+
UPDATE schema_change_log
|
|
72
|
+
SET status = 'rolled_back',
|
|
73
|
+
notes = 'D2 rollback executado',
|
|
74
|
+
updated_at = CURRENT_TIMESTAMP
|
|
75
|
+
WHERE migration_key = @migration_key;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
-- D2 (2026-03-07) - Auth hardening follow-up
|
|
2
|
+
-- Scope: distributed login throttle + hashed sensitive metadata for password recovery
|
|
3
|
+
|
|
4
|
+
SET @migration_key := '20260307_d2_auth_hardening';
|
|
5
|
+
|
|
6
|
+
DROP PROCEDURE IF EXISTS __ensure_column;
|
|
7
|
+
DROP PROCEDURE IF EXISTS __ensure_index;
|
|
8
|
+
|
|
9
|
+
DELIMITER $$
|
|
10
|
+
CREATE PROCEDURE __ensure_column(IN p_table_name VARCHAR(64), IN p_column_name VARCHAR(64), IN p_ddl TEXT)
|
|
11
|
+
BEGIN
|
|
12
|
+
IF NOT EXISTS (
|
|
13
|
+
SELECT 1
|
|
14
|
+
FROM information_schema.columns
|
|
15
|
+
WHERE table_schema = DATABASE()
|
|
16
|
+
AND table_name = p_table_name
|
|
17
|
+
AND column_name = p_column_name
|
|
18
|
+
) THEN
|
|
19
|
+
SET @ddl = p_ddl;
|
|
20
|
+
PREPARE stmt FROM @ddl;
|
|
21
|
+
EXECUTE stmt;
|
|
22
|
+
DEALLOCATE PREPARE stmt;
|
|
23
|
+
END IF;
|
|
24
|
+
END$$
|
|
25
|
+
|
|
26
|
+
CREATE PROCEDURE __ensure_index(IN p_table_name VARCHAR(64), IN p_index_name VARCHAR(64), IN p_ddl TEXT)
|
|
27
|
+
BEGIN
|
|
28
|
+
IF NOT EXISTS (
|
|
29
|
+
SELECT 1
|
|
30
|
+
FROM information_schema.statistics
|
|
31
|
+
WHERE table_schema = DATABASE()
|
|
32
|
+
AND table_name = p_table_name
|
|
33
|
+
AND index_name = p_index_name
|
|
34
|
+
) THEN
|
|
35
|
+
SET @ddl = p_ddl;
|
|
36
|
+
PREPARE stmt FROM @ddl;
|
|
37
|
+
EXECUTE stmt;
|
|
38
|
+
DEALLOCATE PREPARE stmt;
|
|
39
|
+
END IF;
|
|
40
|
+
END$$
|
|
41
|
+
DELIMITER ;
|
|
42
|
+
|
|
43
|
+
CREATE TABLE IF NOT EXISTS web_user_password_login_throttle (
|
|
44
|
+
identity_hash BINARY(32) NOT NULL,
|
|
45
|
+
failed_attempts SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
|
46
|
+
last_failed_at TIMESTAMP NULL DEFAULT NULL,
|
|
47
|
+
locked_until TIMESTAMP NULL DEFAULT NULL,
|
|
48
|
+
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
|
49
|
+
updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
50
|
+
PRIMARY KEY (identity_hash),
|
|
51
|
+
KEY idx_web_user_password_login_throttle_locked_until (locked_until),
|
|
52
|
+
KEY idx_web_user_password_login_throttle_failed (failed_attempts, last_failed_at)
|
|
53
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
54
|
+
|
|
55
|
+
CALL __ensure_column(
|
|
56
|
+
'web_user_password_recovery_code',
|
|
57
|
+
'email_hash',
|
|
58
|
+
'ALTER TABLE web_user_password_recovery_code ADD COLUMN email_hash BINARY(32) NULL AFTER email'
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
CALL __ensure_column(
|
|
62
|
+
'web_user_password_recovery_code',
|
|
63
|
+
'requested_ip_hash',
|
|
64
|
+
'ALTER TABLE web_user_password_recovery_code ADD COLUMN requested_ip_hash BINARY(32) NULL AFTER requested_ip'
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
CALL __ensure_column(
|
|
68
|
+
'web_user_password_recovery_code',
|
|
69
|
+
'requested_user_agent_hash',
|
|
70
|
+
'ALTER TABLE web_user_password_recovery_code ADD COLUMN requested_user_agent_hash BINARY(32) NULL AFTER requested_user_agent'
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
CALL __ensure_index(
|
|
74
|
+
'web_user_password_recovery_code',
|
|
75
|
+
'idx_web_user_password_recovery_email_hash_created',
|
|
76
|
+
'CREATE INDEX idx_web_user_password_recovery_email_hash_created ON web_user_password_recovery_code (email_hash, created_at)'
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
CALL __ensure_index(
|
|
80
|
+
'web_user_password_login_throttle',
|
|
81
|
+
'idx_web_user_password_login_throttle_locked_until',
|
|
82
|
+
'CREATE INDEX idx_web_user_password_login_throttle_locked_until ON web_user_password_login_throttle (locked_until)'
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
CALL __ensure_index(
|
|
86
|
+
'web_user_password_login_throttle',
|
|
87
|
+
'idx_web_user_password_login_throttle_failed',
|
|
88
|
+
'CREATE INDEX idx_web_user_password_login_throttle_failed ON web_user_password_login_throttle (failed_attempts, last_failed_at)'
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
DROP PROCEDURE IF EXISTS __ensure_column;
|
|
92
|
+
DROP PROCEDURE IF EXISTS __ensure_index;
|
|
93
|
+
|
|
94
|
+
INSERT INTO schema_change_log (migration_key, phase, status, notes)
|
|
95
|
+
VALUES (@migration_key, 'D2', 'applied', 'Distributed login throttle + hashed recovery sensitive metadata')
|
|
96
|
+
ON DUPLICATE KEY UPDATE
|
|
97
|
+
phase = VALUES(phase),
|
|
98
|
+
status = 'applied',
|
|
99
|
+
notes = VALUES(notes),
|
|
100
|
+
updated_at = CURRENT_TIMESTAMP;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
-- D+7 rollback
|
|
2
|
+
|
|
3
|
+
SET @migration_key := '20260314_d7_canonical_sender';
|
|
4
|
+
|
|
5
|
+
DROP PROCEDURE IF EXISTS __drop_column_if_exists;
|
|
6
|
+
DROP PROCEDURE IF EXISTS __drop_index_if_exists;
|
|
7
|
+
|
|
8
|
+
DELIMITER $$
|
|
9
|
+
CREATE PROCEDURE __drop_column_if_exists(IN p_table_name VARCHAR(64), IN p_column_name VARCHAR(64))
|
|
10
|
+
BEGIN
|
|
11
|
+
IF EXISTS (
|
|
12
|
+
SELECT 1
|
|
13
|
+
FROM information_schema.columns
|
|
14
|
+
WHERE table_schema = DATABASE()
|
|
15
|
+
AND table_name = p_table_name
|
|
16
|
+
AND column_name = p_column_name
|
|
17
|
+
) THEN
|
|
18
|
+
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` DROP COLUMN `', p_column_name, '`');
|
|
19
|
+
PREPARE stmt FROM @ddl;
|
|
20
|
+
EXECUTE stmt;
|
|
21
|
+
DEALLOCATE PREPARE stmt;
|
|
22
|
+
END IF;
|
|
23
|
+
END$$
|
|
24
|
+
|
|
25
|
+
CREATE PROCEDURE __drop_index_if_exists(IN p_table_name VARCHAR(64), IN p_index_name VARCHAR(64))
|
|
26
|
+
BEGIN
|
|
27
|
+
IF EXISTS (
|
|
28
|
+
SELECT 1
|
|
29
|
+
FROM information_schema.statistics
|
|
30
|
+
WHERE table_schema = DATABASE()
|
|
31
|
+
AND table_name = p_table_name
|
|
32
|
+
AND index_name = p_index_name
|
|
33
|
+
) THEN
|
|
34
|
+
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` DROP INDEX `', p_index_name, '`');
|
|
35
|
+
PREPARE stmt FROM @ddl;
|
|
36
|
+
EXECUTE stmt;
|
|
37
|
+
DEALLOCATE PREPARE stmt;
|
|
38
|
+
END IF;
|
|
39
|
+
END$$
|
|
40
|
+
DELIMITER ;
|
|
41
|
+
|
|
42
|
+
CALL __drop_index_if_exists('messages', 'idx_messages_chat_canonical_sender_timestamp');
|
|
43
|
+
CALL __drop_index_if_exists('messages', 'idx_messages_canonical_sender_timestamp');
|
|
44
|
+
CALL __drop_column_if_exists('messages', 'canonical_sender_id');
|
|
45
|
+
|
|
46
|
+
UPDATE schema_change_log
|
|
47
|
+
SET status = 'rolled_back',
|
|
48
|
+
notes = 'D+7 rollback executed',
|
|
49
|
+
updated_at = CURRENT_TIMESTAMP
|
|
50
|
+
WHERE migration_key = @migration_key;
|
|
51
|
+
|
|
52
|
+
DROP PROCEDURE IF EXISTS __drop_column_if_exists;
|
|
53
|
+
DROP PROCEDURE IF EXISTS __drop_index_if_exists;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
-- D+7 (2026-03-14) - Small migration
|
|
2
|
+
-- Scope: canonical sender column for high-volume ranking/analytics queries
|
|
3
|
+
|
|
4
|
+
SET @migration_key := '20260314_d7_canonical_sender';
|
|
5
|
+
|
|
6
|
+
DROP PROCEDURE IF EXISTS __ensure_column;
|
|
7
|
+
DROP PROCEDURE IF EXISTS __drop_column_if_exists;
|
|
8
|
+
DROP PROCEDURE IF EXISTS __ensure_index;
|
|
9
|
+
DROP PROCEDURE IF EXISTS __backfill_messages_canonical_sender;
|
|
10
|
+
|
|
11
|
+
DELIMITER $$
|
|
12
|
+
CREATE PROCEDURE __ensure_column(IN p_table_name VARCHAR(64), IN p_column_name VARCHAR(64), IN p_ddl TEXT)
|
|
13
|
+
BEGIN
|
|
14
|
+
IF NOT EXISTS (
|
|
15
|
+
SELECT 1
|
|
16
|
+
FROM information_schema.columns
|
|
17
|
+
WHERE table_schema = DATABASE()
|
|
18
|
+
AND table_name = p_table_name
|
|
19
|
+
AND column_name = p_column_name
|
|
20
|
+
) THEN
|
|
21
|
+
SET @ddl = p_ddl;
|
|
22
|
+
PREPARE stmt FROM @ddl;
|
|
23
|
+
EXECUTE stmt;
|
|
24
|
+
DEALLOCATE PREPARE stmt;
|
|
25
|
+
END IF;
|
|
26
|
+
END$$
|
|
27
|
+
|
|
28
|
+
CREATE PROCEDURE __drop_column_if_exists(IN p_table_name VARCHAR(64), IN p_column_name VARCHAR(64))
|
|
29
|
+
BEGIN
|
|
30
|
+
IF EXISTS (
|
|
31
|
+
SELECT 1
|
|
32
|
+
FROM information_schema.columns
|
|
33
|
+
WHERE table_schema = DATABASE()
|
|
34
|
+
AND table_name = p_table_name
|
|
35
|
+
AND column_name = p_column_name
|
|
36
|
+
) THEN
|
|
37
|
+
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` DROP COLUMN `', p_column_name, '`');
|
|
38
|
+
PREPARE stmt FROM @ddl;
|
|
39
|
+
EXECUTE stmt;
|
|
40
|
+
DEALLOCATE PREPARE stmt;
|
|
41
|
+
END IF;
|
|
42
|
+
END$$
|
|
43
|
+
|
|
44
|
+
CREATE PROCEDURE __ensure_index(IN p_table_name VARCHAR(64), IN p_index_name VARCHAR(64), IN p_ddl TEXT)
|
|
45
|
+
BEGIN
|
|
46
|
+
IF NOT EXISTS (
|
|
47
|
+
SELECT 1
|
|
48
|
+
FROM information_schema.statistics
|
|
49
|
+
WHERE table_schema = DATABASE()
|
|
50
|
+
AND table_name = p_table_name
|
|
51
|
+
AND index_name = p_index_name
|
|
52
|
+
) THEN
|
|
53
|
+
SET @ddl = p_ddl;
|
|
54
|
+
PREPARE stmt FROM @ddl;
|
|
55
|
+
EXECUTE stmt;
|
|
56
|
+
DEALLOCATE PREPARE stmt;
|
|
57
|
+
END IF;
|
|
58
|
+
END$$
|
|
59
|
+
|
|
60
|
+
CREATE PROCEDURE __backfill_messages_canonical_sender(IN p_batch_size BIGINT UNSIGNED)
|
|
61
|
+
BEGIN
|
|
62
|
+
DECLARE v_min BIGINT UNSIGNED DEFAULT 0;
|
|
63
|
+
DECLARE v_max BIGINT UNSIGNED DEFAULT 0;
|
|
64
|
+
DECLARE v_cursor BIGINT UNSIGNED DEFAULT 0;
|
|
65
|
+
|
|
66
|
+
SELECT COALESCE(MIN(id), 0), COALESCE(MAX(id), 0)
|
|
67
|
+
INTO v_min, v_max
|
|
68
|
+
FROM messages
|
|
69
|
+
WHERE canonical_sender_id IS NULL;
|
|
70
|
+
|
|
71
|
+
SET v_cursor = v_min;
|
|
72
|
+
|
|
73
|
+
WHILE v_cursor > 0 AND v_cursor <= v_max DO
|
|
74
|
+
UPDATE messages m
|
|
75
|
+
LEFT JOIN lid_map lm
|
|
76
|
+
ON lm.lid = m.sender_id
|
|
77
|
+
AND lm.jid IS NOT NULL
|
|
78
|
+
SET m.canonical_sender_id = COALESCE(lm.jid, m.sender_id)
|
|
79
|
+
WHERE m.id BETWEEN v_cursor AND (v_cursor + p_batch_size - 1)
|
|
80
|
+
AND m.canonical_sender_id IS NULL;
|
|
81
|
+
|
|
82
|
+
SET v_cursor = v_cursor + p_batch_size;
|
|
83
|
+
END WHILE;
|
|
84
|
+
END$$
|
|
85
|
+
DELIMITER ;
|
|
86
|
+
|
|
87
|
+
CALL __ensure_column('messages', 'canonical_sender_id', 'ALTER TABLE messages ADD COLUMN canonical_sender_id VARCHAR(255) NULL AFTER sender_id');
|
|
88
|
+
|
|
89
|
+
CALL __ensure_index('messages', 'idx_messages_canonical_sender_timestamp', 'CREATE INDEX idx_messages_canonical_sender_timestamp ON messages (canonical_sender_id, timestamp)');
|
|
90
|
+
CALL __ensure_index('messages', 'idx_messages_chat_canonical_sender_timestamp', 'CREATE INDEX idx_messages_chat_canonical_sender_timestamp ON messages (chat_id, canonical_sender_id, timestamp)');
|
|
91
|
+
|
|
92
|
+
-- Backfill in chunks (adjust batch size according to table size / write pressure)
|
|
93
|
+
CALL __backfill_messages_canonical_sender(50000);
|
|
94
|
+
|
|
95
|
+
-- Safety pass for rows inserted during chunk loop
|
|
96
|
+
UPDATE messages m
|
|
97
|
+
LEFT JOIN lid_map lm
|
|
98
|
+
ON lm.lid = m.sender_id
|
|
99
|
+
AND lm.jid IS NOT NULL
|
|
100
|
+
SET m.canonical_sender_id = COALESCE(lm.jid, m.sender_id)
|
|
101
|
+
WHERE m.canonical_sender_id IS NULL;
|
|
102
|
+
|
|
103
|
+
INSERT INTO schema_change_log (migration_key, phase, status, notes)
|
|
104
|
+
VALUES (@migration_key, 'D+7', 'applied', 'messages.canonical_sender_id + backfill + indexes')
|
|
105
|
+
ON DUPLICATE KEY UPDATE
|
|
106
|
+
phase = VALUES(phase),
|
|
107
|
+
status = 'applied',
|
|
108
|
+
notes = VALUES(notes),
|
|
109
|
+
updated_at = CURRENT_TIMESTAMP;
|
|
110
|
+
|
|
111
|
+
DROP PROCEDURE IF EXISTS __ensure_column;
|
|
112
|
+
DROP PROCEDURE IF EXISTS __drop_column_if_exists;
|
|
113
|
+
DROP PROCEDURE IF EXISTS __ensure_index;
|
|
114
|
+
DROP PROCEDURE IF EXISTS __backfill_messages_canonical_sender;
|