iatoolkit 2.76.4__tar.gz → 2.76.5__tar.gz

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.
Files changed (282) hide show
  1. {iatoolkit-2.76.4/src/iatoolkit.egg-info → iatoolkit-2.76.5}/PKG-INFO +1 -1
  2. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/__init__.py +1 -1
  3. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/core.py +2 -0
  4. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/locales/en.yaml +1 -0
  5. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/locales/es.yaml +1 -0
  6. iatoolkit-2.76.5/src/iatoolkit/services/signup_guard_service.py +156 -0
  7. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/signup.html +6 -0
  8. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/signup_view.py +30 -14
  9. {iatoolkit-2.76.4 → iatoolkit-2.76.5/src/iatoolkit.egg-info}/PKG-INFO +1 -1
  10. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit.egg-info/SOURCES.txt +1 -0
  11. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/LICENSE +0 -0
  12. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/LICENSE_COMMUNITY.md +0 -0
  13. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/pyproject.toml +0 -0
  14. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/readme.md +0 -0
  15. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/setup.cfg +0 -0
  16. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/base_company.py +0 -0
  17. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/cli_commands.py +0 -0
  18. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/__init__.py +0 -0
  19. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/access.py +0 -0
  20. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/bridge_validation.py +0 -0
  21. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/company_paths.py +0 -0
  22. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/exceptions.py +0 -0
  23. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/interfaces/__init__.py +0 -0
  24. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/interfaces/asset_storage.py +0 -0
  25. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/interfaces/database_provider.py +0 -0
  26. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/interfaces/history_compaction_trigger.py +0 -0
  27. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/interfaces/memory_compilation_trigger.py +0 -0
  28. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/interfaces/secret_provider.py +0 -0
  29. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/interfaces/signup_policy_resolver.py +0 -0
  30. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/interfaces/web_search_provider.py +0 -0
  31. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/memory_tools.py +0 -0
  32. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/model_registry.py +0 -0
  33. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/routes.py +0 -0
  34. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/search_terms.py +0 -0
  35. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/secret_resolver.py +0 -0
  36. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/session_manager.py +0 -0
  37. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/text_splitter.py +0 -0
  38. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/url_safety.py +0 -0
  39. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/common/util.py +0 -0
  40. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/company_registry.py +0 -0
  41. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/__init__.py +0 -0
  42. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/llm_capabilities.yaml +0 -0
  43. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_agents/history_compaction.prompt +0 -0
  44. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_agents/memory_compiler.prompt +0 -0
  45. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_agents/memory_correction.prompt +0 -0
  46. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_agents/memory_document_ingest.prompt +0 -0
  47. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_agents/memory_image_ingest.prompt +0 -0
  48. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_agents/memory_meeting_ingest.prompt +0 -0
  49. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_agents/memory_question_review.prompt +0 -0
  50. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_agents_pack.yaml +0 -0
  51. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/channel_business_identity.prompt +0 -0
  52. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/channel_conversation_continuity.prompt +0 -0
  53. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/channel_response_style.prompt +0 -0
  54. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/chat_state_rules.prompt +0 -0
  55. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/chat_user_profile.prompt +0 -0
  56. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/core_identity.prompt +0 -0
  57. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/email_output.prompt +0 -0
  58. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/file_download_output.prompt +0 -0
  59. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/format_styles.prompt +0 -0
  60. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/html_structures.prompt +0 -0
  61. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/links_documents.prompt +0 -0
  62. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/memory_usage.prompt +0 -0
  63. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/multimodal_basics.prompt +0 -0
  64. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/output_basics.prompt +0 -0
  65. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/presentation_formatting.prompt +0 -0
  66. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/query_main.prompt +0 -0
  67. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/sql_aggregation_scope.prompt +0 -0
  68. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/sql_casting.prompt +0 -0
  69. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/sql_core.prompt +0 -0
  70. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/sql_jsonb.prompt +0 -0
  71. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/sql_mysql_casting.prompt +0 -0
  72. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/sql_mysql_json.prompt +0 -0
  73. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/sql_redshift_basics.prompt +0 -0
  74. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/sql_redshift_types.prompt +0 -0
  75. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts/tool_html_passthrough.prompt +0 -0
  76. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_prompts_pack.yaml +0 -0
  77. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/config/system_tools_pack.yaml +0 -0
  78. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/__init__.py +0 -0
  79. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/brevo_mail_app.py +0 -0
  80. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/call_service.py +0 -0
  81. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/connectors/__init__.py +0 -0
  82. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
  83. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
  84. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
  85. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
  86. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
  87. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
  88. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/google_auth_client.py +0 -0
  89. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/google_chat_app.py +0 -0
  90. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/inference_embeddings_client.py +0 -0
  91. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/inference_handler.py +0 -0
  92. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/jina_embeddings_client.py +0 -0
  93. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_gateway_resolver.py +0 -0
  94. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_providers/__init__.py +0 -0
  95. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_providers/anthropic_adapter.py +0 -0
  96. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_providers/deepseek_adapter.py +0 -0
  97. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_providers/gemini_adapter.py +0 -0
  98. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_providers/openai_adapter.py +0 -0
  99. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_providers/openai_compatible_chat_adapter.py +0 -0
  100. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_providers/openrouter_adapter.py +0 -0
  101. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_proxy.py +0 -0
  102. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/llm_response.py +0 -0
  103. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/infra/redis_session_manager.py +0 -0
  104. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/__init__.py +0 -0
  105. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/advisory_lock.py +0 -0
  106. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/api_key_repo.py +0 -0
  107. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/bridge_repo.py +0 -0
  108. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/database_manager.py +0 -0
  109. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/document_repo.py +0 -0
  110. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/env_secret_provider.py +0 -0
  111. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/filesystem_asset_repository.py +0 -0
  112. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/knowledge_wiki_repo.py +0 -0
  113. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
  114. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/mcp_token_repo.py +0 -0
  115. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/memory_question_repo.py +0 -0
  116. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/memory_repo.py +0 -0
  117. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/memory_usage_repo.py +0 -0
  118. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/models.py +0 -0
  119. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/profile_repo.py +0 -0
  120. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/prompt_resource_repo.py +0 -0
  121. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/sql_dataset_repo.py +0 -0
  122. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/sql_source_repo.py +0 -0
  123. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/repositories/vs_repo.py +0 -0
  124. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/runtime_logging.py +0 -0
  125. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/__init__.py +0 -0
  126. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/api_key_service.py +0 -0
  127. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/attachment_policy_service.py +0 -0
  128. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/auth_service.py +0 -0
  129. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/branding_service.py +0 -0
  130. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/company_context_service.py +0 -0
  131. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/configuration_service.py +0 -0
  132. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/context_builder_service.py +0 -0
  133. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/dispatcher_service.py +0 -0
  134. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/embedding_service.py +0 -0
  135. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/excel_service.py +0 -0
  136. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/file_processor_service.py +0 -0
  137. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/history_compaction_service.py +0 -0
  138. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/history_manager_service.py +0 -0
  139. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/http_tool_service.py +0 -0
  140. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/i18n_service.py +0 -0
  141. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/inference_service.py +0 -0
  142. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/jwt_service.py +0 -0
  143. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/knowledge_base_service.py +0 -0
  144. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/language_service.py +0 -0
  145. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/license_service.py +0 -0
  146. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/llm_client_service.py +0 -0
  147. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/mail_service.py +0 -0
  148. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/markdown_wiki_service.py +0 -0
  149. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/mcp_token_service.py +0 -0
  150. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/memory_compiler_service.py +0 -0
  151. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/memory_lookup_policy_service.py +0 -0
  152. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/memory_question_service.py +0 -0
  153. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/memory_service.py +0 -0
  154. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/memory_sources.py +0 -0
  155. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/memory_usage_service.py +0 -0
  156. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/memory_wiki_service.py +0 -0
  157. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/noop_history_compaction_trigger.py +0 -0
  158. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/noop_memory_compilation_trigger.py +0 -0
  159. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/operator_identity_service.py +0 -0
  160. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/__init__.py +0 -0
  161. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/contracts.py +0 -0
  162. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/image_normalizer.py +0 -0
  163. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/parsing_service.py +0 -0
  164. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/pdf_ocr_detection.py +0 -0
  165. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/provider_factory.py +0 -0
  166. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/provider_resolver.py +0 -0
  167. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/providers/__init__.py +0 -0
  168. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/providers/basic_provider.py +0 -0
  169. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/providers/docling_provider.py +0 -0
  170. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/parsers/validator.py +0 -0
  171. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/pdf_service.py +0 -0
  172. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/profile_service.py +0 -0
  173. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/prompt_resource_service.py +0 -0
  174. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/prompt_service.py +0 -0
  175. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/query_service.py +0 -0
  176. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/resource_access_scope.py +0 -0
  177. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/signup_policy_resolver.py +0 -0
  178. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/sql_catalog_service.py +0 -0
  179. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/sql_dataset_service.py +0 -0
  180. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/sql_service.py +0 -0
  181. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/sql_source_service.py +0 -0
  182. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/storage_service.py +0 -0
  183. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/structured_output_service.py +0 -0
  184. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/system_agent_catalog.py +0 -0
  185. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/system_agent_runner.py +0 -0
  186. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/system_prompt_catalog.py +0 -0
  187. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/system_tools.py +0 -0
  188. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/telemetry_service.py +0 -0
  189. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/tenant_wiki_service.py +0 -0
  190. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/tool_output_contract.py +0 -0
  191. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/tool_service.py +0 -0
  192. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/user_feedback_service.py +0 -0
  193. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/user_session_context_service.py +0 -0
  194. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/visual_kb_service.py +0 -0
  195. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/visual_tool_service.py +0 -0
  196. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/warmup_service.py +0 -0
  197. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/web_search/__init__.py +0 -0
  198. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/web_search/provider_factory.py +0 -0
  199. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/web_search/providers/__init__.py +0 -0
  200. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/web_search/providers/brave_provider.py +0 -0
  201. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/web_search_service.py +0 -0
  202. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/services/wiki_page_index_service.py +0 -0
  203. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/images/favicon.ico +0 -0
  204. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/images/favicon.png +0 -0
  205. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/images/fernando.jpeg +0 -0
  206. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/images/iatoolkit_core.png +0 -0
  207. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/images/iatoolkit_logo.png +0 -0
  208. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
  209. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_filepond.js +0 -0
  210. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_header_navigation.js +0 -0
  211. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_help_content.js +0 -0
  212. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_history_button.js +0 -0
  213. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
  214. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_main.js +0 -0
  215. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_memory_button.js +0 -0
  216. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_model_selector.js +0 -0
  217. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
  218. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
  219. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/styles/account.css +0 -0
  220. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/styles/chat_iatoolkit.css +0 -0
  221. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/styles/chat_modal.css +0 -0
  222. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/styles/chat_public.css +0 -0
  223. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/styles/documents.css +0 -0
  224. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/styles/landing_page.css +0 -0
  225. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/styles/llm_output.css +0 -0
  226. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/styles/onboarding.css +0 -0
  227. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/static/styles/wiki_page.css +0 -0
  228. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/_chat_header.html +0 -0
  229. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/_company_header.html +0 -0
  230. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/_login_widget.html +0 -0
  231. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/account.html +0 -0
  232. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/base.html +0 -0
  233. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/change_password.html +0 -0
  234. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/chat.html +0 -0
  235. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/chat_memory_modal.html +0 -0
  236. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/chat_modals.html +0 -0
  237. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/error.html +0 -0
  238. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/forgot_password.html +0 -0
  239. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/home_hosted_default.html +0 -0
  240. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/login_global.html +0 -0
  241. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/memory/wiki_schema.md +0 -0
  242. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/pdf/base.html +0 -0
  243. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/pdf/letter.html +0 -0
  244. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/pdf/report.html +0 -0
  245. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/pdf/simple.html +0 -0
  246. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/templates/wiki_page.html +0 -0
  247. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/__init__.py +0 -0
  248. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/account_view.py +0 -0
  249. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/api_key_api_view.py +0 -0
  250. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/base_login_view.py +0 -0
  251. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/categories_api_view.py +0 -0
  252. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/change_password_view.py +0 -0
  253. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/chat_context_preview_api_view.py +0 -0
  254. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/chat_view.py +0 -0
  255. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/configuration_api_view.py +0 -0
  256. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/connectors_api_view.py +0 -0
  257. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/embedding_api_view.py +0 -0
  258. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/forgot_password_view.py +0 -0
  259. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/help_content_api_view.py +0 -0
  260. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/history_api_view.py +0 -0
  261. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/home_view.py +0 -0
  262. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/init_context_api_view.py +0 -0
  263. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/llmquery_api_view.py +0 -0
  264. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/load_document_api_view.py +0 -0
  265. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/login_view.py +0 -0
  266. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/logout_api_view.py +0 -0
  267. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/memory_api_view.py +0 -0
  268. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/profile_api_view.py +0 -0
  269. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/prompt_api_view.py +0 -0
  270. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/prompt_context_preview_api_view.py +0 -0
  271. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/prompt_resource_api_view.py +0 -0
  272. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/rag_api_view.py +0 -0
  273. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/root_redirect_view.py +0 -0
  274. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/static_page_view.py +0 -0
  275. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/tool_api_view.py +0 -0
  276. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
  277. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/users_api_view.py +0 -0
  278. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/verify_user_view.py +0 -0
  279. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit/views/wiki_page_view.py +0 -0
  280. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
  281. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit.egg-info/requires.txt +0 -0
  282. {iatoolkit-2.76.4 → iatoolkit-2.76.5}/src/iatoolkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 2.76.4
3
+ Version: 2.76.5
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # IAToolkit is open source software.
5
5
 
6
- __version__ = "2.76.4"
6
+ __version__ = "2.76.5"
7
7
 
8
8
  # Expose main classes and functions at the top level of the package
9
9
 
@@ -460,6 +460,7 @@ class IAToolkit:
460
460
  from iatoolkit.services.sql_source_service import SqlSourceService
461
461
  from iatoolkit.services.dispatcher_service import Dispatcher
462
462
  from iatoolkit.services.branding_service import BrandingService
463
+ from iatoolkit.services.signup_guard_service import SignupGuardService
463
464
  from iatoolkit.services.i18n_service import I18nService
464
465
  from iatoolkit.services.language_service import LanguageService
465
466
  from iatoolkit.services.configuration_service import ConfigurationService
@@ -506,6 +507,7 @@ class IAToolkit:
506
507
  binder.bind(SqlSourceService, to=SqlSourceService)
507
508
  binder.bind(Dispatcher, to=Dispatcher)
508
509
  binder.bind(BrandingService, to=BrandingService)
510
+ binder.bind(SignupGuardService, to=SignupGuardService)
509
511
  binder.bind(I18nService, to=I18nService)
510
512
  binder.bind(LanguageService, to=LanguageService)
511
513
  # this class can be setup before by iatoolkit enterprise.
@@ -2859,6 +2859,7 @@ errors:
2859
2859
  user_already_registered: "The user with email '{email}' already exists in this company."
2860
2860
  password_mismatch: "The passwords do not match. Please try again."
2861
2861
  signup_not_allowed: "Signup is not allowed for this company. Please contact an administrator."
2862
+ form_expired: "The form has expired. Please try again."
2862
2863
  invitation_required: "A valid invitation is required to join this company. Ask your administrator for a new link."
2863
2864
  change_password:
2864
2865
  token_expired: "The password change link has expired. Please request a new one."
@@ -2878,6 +2878,7 @@ errors:
2878
2878
  user_already_registered: "El usuario con email '{email}' ya existe en esta empresa."
2879
2879
  password_mismatch: "Las contraseñas no coinciden. Por favor, inténtalo de nuevo."
2880
2880
  signup_not_allowed: "El registro no está habilitado para esta empresa. Contacta a un administrador."
2881
+ form_expired: "El formulario expiró. Por favor, inténtalo de nuevo."
2881
2882
  invitation_required: "Necesitas una invitación vigente para unirte a esta empresa. Solicita un nuevo enlace al administrador."
2882
2883
  change_password:
2883
2884
  token_expired: "El enlace de cambio de contraseña ha expirado. Por favor, solicita uno nuevo."
@@ -0,0 +1,156 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Product: IAToolkit
3
+ #
4
+ # IAToolkit is open source software.
5
+
6
+ """Bot detection for the public signup form.
7
+
8
+ Bots fill the signup form with random names and real people's emails, so every
9
+ attempt makes us send a verification email nobody asked for. The checks here run
10
+ before any user is created or any email is sent, and add no step for a person:
11
+
12
+ - a signed form token issued when the page is rendered: a POST without it never
13
+ loaded the page, and one submitted a few seconds after render was not typed;
14
+ - a honeypot field hidden from people, which bots fill in;
15
+ - per-IP and per-email rate limits in Redis.
16
+
17
+ A rejected bot is answered exactly like a successful signup (see SignupView), so
18
+ it cannot learn which check stopped it. Only an expired token is reported, since
19
+ that is a person who left the page open.
20
+ """
21
+
22
+ import logging
23
+ import os
24
+ import time
25
+
26
+ from itsdangerous import BadSignature, SignatureExpired, URLSafeTimedSerializer
27
+
28
+ from iatoolkit.infra.redis_session_manager import RedisSessionManager
29
+
30
+
31
+ class SignupGuardService:
32
+ FORM_TOKEN_FIELD = 'form_token'
33
+ HONEYPOT_FIELD = 'website'
34
+
35
+ MIN_FILL_SECONDS = 3
36
+ FORM_TOKEN_MAX_AGE_SECONDS = 2 * 60 * 60
37
+ MAX_SIGNUPS_PER_IP = 5
38
+ IP_WINDOW_SECONDS = 60 * 60
39
+ MAX_SIGNUPS_PER_EMAIL = 3
40
+ EMAIL_WINDOW_SECONDS = 24 * 60 * 60
41
+
42
+ # outcomes of check()
43
+ ALLOWED = None
44
+ EXPIRED = 'form_expired'
45
+
46
+ _FORM_TOKEN_SALT = 'signup-form'
47
+ _GMAIL_DOMAINS = {'gmail.com', 'googlemail.com'}
48
+
49
+ def __init__(self):
50
+ self.serializer = URLSafeTimedSerializer(os.getenv("IATOOLKIT_SECRET_KEY"))
51
+
52
+ @staticmethod
53
+ def is_enabled() -> bool:
54
+ # automated end-to-end tests submit the form faster than a person
55
+ return os.getenv('IATOOLKIT_SIGNUP_BOT_GUARD', 'on').strip().lower() not in ('off', 'false', '0')
56
+
57
+ def issue_form_token(self, company_short_name: str) -> str:
58
+ return self.serializer.dumps(company_short_name, salt=self._FORM_TOKEN_SALT)
59
+
60
+ def check(self, company_short_name: str, form, client_ip: str | None, email: str | None) -> str | None:
61
+ """Return None when the signup may proceed, or the reason it was rejected."""
62
+ if not self.is_enabled():
63
+ return self.ALLOWED
64
+
65
+ reason = self._check_form(company_short_name, form)
66
+ if reason is None:
67
+ reason = self._check_rate_limits(company_short_name, client_ip, email)
68
+
69
+ if reason is not None:
70
+ email_domain = (email or '').rpartition('@')[2].lower() or '-'
71
+ logging.warning(
72
+ "signup rejected: reason=%s company=%s ip=%s email_domain=%s",
73
+ reason, company_short_name, client_ip or '-', email_domain,
74
+ )
75
+ return reason
76
+
77
+ def _check_form(self, company_short_name: str, form) -> str | None:
78
+ if (form.get(self.HONEYPOT_FIELD) or '').strip():
79
+ return 'honeypot'
80
+
81
+ token = form.get(self.FORM_TOKEN_FIELD)
82
+ if not token:
83
+ return 'missing_form_token'
84
+ try:
85
+ token_company, issued_at = self.serializer.loads(
86
+ token,
87
+ salt=self._FORM_TOKEN_SALT,
88
+ max_age=self.FORM_TOKEN_MAX_AGE_SECONDS,
89
+ return_timestamp=True,
90
+ )
91
+ except SignatureExpired:
92
+ return self.EXPIRED
93
+ except BadSignature:
94
+ return 'invalid_form_token'
95
+
96
+ if token_company != company_short_name:
97
+ return 'invalid_form_token'
98
+ if time.time() - issued_at.timestamp() < self.MIN_FILL_SECONDS:
99
+ return 'too_fast'
100
+ return None
101
+
102
+ def _check_rate_limits(self, company_short_name: str, client_ip: str | None, email: str | None) -> str | None:
103
+ if client_ip and self._hit(f'signup_guard:ip:{client_ip}', self.IP_WINDOW_SECONDS) > self.MAX_SIGNUPS_PER_IP:
104
+ return 'ip_rate_limit'
105
+
106
+ normalized_email = self.normalize_email(email)
107
+ if normalized_email and self._hit(
108
+ f'signup_guard:email:{normalized_email}', self.EMAIL_WINDOW_SECONDS) > self.MAX_SIGNUPS_PER_EMAIL:
109
+ return 'email_rate_limit'
110
+ return None
111
+
112
+ @staticmethod
113
+ def _hit(key: str, window_seconds: int) -> int:
114
+ """Count one attempt in a fixed window. Fails open: Redis down never blocks a signup."""
115
+ try:
116
+ pipe = RedisSessionManager.pipeline()
117
+ pipe.incr(key)
118
+ pipe.ttl(key)
119
+ count, ttl = pipe.execute()
120
+ if ttl is None or int(ttl) < 0:
121
+ # first hit of the window (or a key left without expiry)
122
+ RedisSessionManager.pipeline().expire(key, window_seconds).execute()
123
+ return int(count)
124
+ except Exception as e:
125
+ logging.warning("signup guard: rate limit unavailable (%s)", e)
126
+ return 0
127
+
128
+ @classmethod
129
+ def normalize_email(cls, email: str | None) -> str:
130
+ """One key per mailbox: Gmail ignores dots and +tags, so bots vary them."""
131
+ local, _, domain = str(email or '').strip().lower().partition('@')
132
+ if not local or not domain:
133
+ return ''
134
+ local = local.split('+', 1)[0]
135
+ if domain in cls._GMAIL_DOMAINS:
136
+ local = local.replace('.', '')
137
+ domain = 'gmail.com'
138
+ return f'{local}@{domain}'
139
+
140
+ @staticmethod
141
+ def client_ip(request) -> str | None:
142
+ """The client IP as seen by our own proxy.
143
+
144
+ The app sits behind one proxy (the platform router) that appends the real
145
+ client to X-Forwarded-For; anything to its left was sent by the client and
146
+ can be forged. IATOOLKIT_TRUSTED_PROXY_HOPS covers an extra proxy in front
147
+ (e.g. a CDN).
148
+ """
149
+ forwarded = [part.strip() for part in request.headers.get('X-Forwarded-For', '').split(',') if part.strip()]
150
+ try:
151
+ hops = max(1, int(os.getenv('IATOOLKIT_TRUSTED_PROXY_HOPS', '1')))
152
+ except ValueError:
153
+ hops = 1
154
+ if forwarded:
155
+ return forwarded[-hops] if len(forwarded) >= hops else forwarded[0]
156
+ return request.remote_addr
@@ -40,6 +40,12 @@
40
40
 
41
41
  <form action="{{ url_for('signup', company_short_name=company_short_name) }}" method="post">
42
42
  {% if invite_token %}<input type="hidden" name="invite_token" value="{{ invite_token }}">{% endif %}
43
+ <input type="hidden" name="form_token" value="{{ form_token }}">
44
+ <!-- honeypot: hidden from people, bots fill it in -->
45
+ <div style="position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden;" aria-hidden="true">
46
+ <label for="website">Website</label>
47
+ <input type="text" id="website" name="website" tabindex="-1" autocomplete="off" value="">
48
+ </div>
43
49
  <div class="mb-3">
44
50
  <label for="email" class="form-label text-secondary">{{ t('ui.signup.email_label') }}</label>
45
51
  <input type="email" autocomplete="off" id="email" name="email"
@@ -8,6 +8,7 @@ from flask import render_template, request, url_for, redirect, flash, make_respo
8
8
  from iatoolkit.services.profile_service import ProfileService
9
9
  from iatoolkit.services.branding_service import BrandingService
10
10
  from iatoolkit.services.i18n_service import I18nService
11
+ from iatoolkit.services.signup_guard_service import SignupGuardService
11
12
  from injector import inject
12
13
  from itsdangerous import URLSafeTimedSerializer
13
14
  import os
@@ -17,10 +18,12 @@ class SignupView(MethodView):
17
18
  @inject
18
19
  def __init__(self, profile_service: ProfileService,
19
20
  branding_service: BrandingService,
20
- i18n_service: I18nService):
21
+ i18n_service: I18nService,
22
+ signup_guard_service: SignupGuardService):
21
23
  self.profile_service = profile_service
22
24
  self.branding_service = branding_service # 3. Guardar la instancia
23
25
  self.i18n_service = i18n_service
26
+ self.signup_guard_service = signup_guard_service
24
27
 
25
28
  self.serializer = URLSafeTimedSerializer(os.getenv("IATOOLKIT_SECRET_KEY"))
26
29
 
@@ -52,6 +55,7 @@ class SignupView(MethodView):
52
55
  "company_short_name": company_short_name,
53
56
  "branding": branding_data,
54
57
  "lang": current_lang,
58
+ "form_token": self.signup_guard_service.issue_form_token(company_short_name),
55
59
  }
56
60
  if invitation_required or invited_email:
57
61
  template_context.update(invite_token=invite_token, invited_email=invited_email)
@@ -80,19 +84,30 @@ class SignupView(MethodView):
80
84
  current_lang = request.form.get("lang") or request.args.get("lang")
81
85
  invite_token = request.form.get("invite_token") or request.args.get("invite_token")
82
86
 
83
- # create verification token and url for verification
84
- token = self.serializer.dumps(email, salt='email-confirm')
85
- verification_url = url_for('verify_account',
86
- company_short_name=company_short_name,
87
- token=token, _external=True)
88
-
89
- response = self.profile_service.signup(
90
- company_short_name=company_short_name,
91
- email=email,
92
- first_name=first_name, last_name=last_name,
93
- password=password, confirm_password=confirm_password,
94
- verification_url=verification_url,
95
- invite_token=invite_token)
87
+ # bots are stopped before any user is created or any email is sent
88
+ rejection = self.signup_guard_service.check(
89
+ company_short_name, request.form,
90
+ client_ip=self.signup_guard_service.client_ip(request), email=email)
91
+ if rejection == SignupGuardService.EXPIRED:
92
+ response = {"error": self.i18n_service.t('errors.signup.form_expired')}
93
+ elif rejection is not None:
94
+ # answer like a successful signup, so the bot can't tell what stopped it
95
+ flash(self.i18n_service.t('flash_messages.signup_success'), 'success')
96
+ return redirect(url_for('home', company_short_name=company_short_name, lang=current_lang))
97
+ else:
98
+ # create verification token and url for verification
99
+ token = self.serializer.dumps(email, salt='email-confirm')
100
+ verification_url = url_for('verify_account',
101
+ company_short_name=company_short_name,
102
+ token=token, _external=True)
103
+
104
+ response = self.profile_service.signup(
105
+ company_short_name=company_short_name,
106
+ email=email,
107
+ first_name=first_name, last_name=last_name,
108
+ password=password, confirm_password=confirm_password,
109
+ verification_url=verification_url,
110
+ invite_token=invite_token)
96
111
 
97
112
  if "error" in response:
98
113
  flash(response["error"], 'error')
@@ -100,6 +115,7 @@ class SignupView(MethodView):
100
115
  "company_short_name": company_short_name,
101
116
  "branding": branding_data,
102
117
  "lang": current_lang,
118
+ "form_token": self.signup_guard_service.issue_form_token(company_short_name),
103
119
  "form_data": {
104
120
  "first_name": first_name,
105
121
  "last_name": last_name,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 2.76.4
3
+ Version: 2.76.5
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -161,6 +161,7 @@ src/iatoolkit/services/prompt_resource_service.py
161
161
  src/iatoolkit/services/prompt_service.py
162
162
  src/iatoolkit/services/query_service.py
163
163
  src/iatoolkit/services/resource_access_scope.py
164
+ src/iatoolkit/services/signup_guard_service.py
164
165
  src/iatoolkit/services/signup_policy_resolver.py
165
166
  src/iatoolkit/services/sql_catalog_service.py
166
167
  src/iatoolkit/services/sql_dataset_service.py
File without changes
File without changes
File without changes
File without changes