From 970508fcb6b9e2f73dfa19055c94e35ee383f9dc Mon Sep 17 00:00:00 2001 From: -LAN- Date: Mon, 24 Mar 2025 16:45:29 +0800 Subject: [PATCH 1/9] fix: update GitHub Actions workflow to trigger on tags Signed-off-by: -LAN- --- .github/workflows/build-push.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 8e5279fb67..2cd5381bec 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -5,8 +5,8 @@ on: branches: - "main" - "deploy/dev" - release: - types: [published] + tags: + - "*" concurrency: group: build-push-${{ github.head_ref || github.run_id }} From 8e75eb5c631694e409977a0239d57e9bc165f4d7 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Mon, 24 Mar 2025 16:47:06 +0800 Subject: [PATCH 2/9] fix: update version to 0.15.5 in packaging and docker-compose files Sgned-off-by: -LAN- --- api/configs/packaging/__init__.py | 2 +- docker/docker-compose-template.yaml | 6 +++--- docker/docker-compose.yaml | 6 +++--- web/package.json | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/configs/packaging/__init__.py b/api/configs/packaging/__init__.py index 25792cb84a..1cf27e1159 100644 --- a/api/configs/packaging/__init__.py +++ b/api/configs/packaging/__init__.py @@ -9,7 +9,7 @@ class PackagingInfo(BaseSettings): CURRENT_VERSION: str = Field( description="Dify version", - default="0.15.4", + default="0.15.5", ) COMMIT_SHA: str = Field( diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index bca0e1814a..9f1cb3d741 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -2,7 +2,7 @@ x-shared-env: &shared-api-worker-env services: # API service api: - image: langgenius/dify-api:0.15.4 + image: langgenius/dify-api:0.15.5 restart: always environment: # Use the shared environment variables. @@ -25,7 +25,7 @@ services: # worker service # The Celery worker for processing the queue. worker: - image: langgenius/dify-api:0.15.4 + image: langgenius/dify-api:0.15.5 restart: always environment: # Use the shared environment variables. @@ -47,7 +47,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:0.15.4 + image: langgenius/dify-web:0.15.5 restart: always environment: CONSOLE_API_URL: ${CONSOLE_API_URL:-} diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index e47519e4d9..cece2af76d 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -393,7 +393,7 @@ x-shared-env: &shared-api-worker-env services: # API service api: - image: langgenius/dify-api:0.15.4 + image: langgenius/dify-api:0.15.5 restart: always environment: # Use the shared environment variables. @@ -416,7 +416,7 @@ services: # worker service # The Celery worker for processing the queue. worker: - image: langgenius/dify-api:0.15.4 + image: langgenius/dify-api:0.15.5 restart: always environment: # Use the shared environment variables. @@ -438,7 +438,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:0.15.4 + image: langgenius/dify-web:0.15.5 restart: always environment: CONSOLE_API_URL: ${CONSOLE_API_URL:-} diff --git a/web/package.json b/web/package.json index 2e10d9c5ad..da66815a7a 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "dify-web", - "version": "0.15.4", + "version": "0.15.5", "private": true, "engines": { "node": ">=18.17.0" From fe1846c437a974e0e7f1948b74d041799b972f28 Mon Sep 17 00:00:00 2001 From: "Alexi.F" <654973939@qq.com> Date: Sun, 30 Mar 2025 13:04:12 +0800 Subject: [PATCH 3/9] fix: change gemini-2.0-flash to validate google api #17082 (#17115) --- .../model_providers/google/google.py | 4 +- .../model_providers/google/llm/_position.yaml | 2 - .../google/llm/gemini-pro-vision.yaml | 35 ----------------- .../google/llm/gemini-pro.yaml | 39 ------------------- 4 files changed, 2 insertions(+), 78 deletions(-) delete mode 100644 api/core/model_runtime/model_providers/google/llm/gemini-pro-vision.yaml delete mode 100644 api/core/model_runtime/model_providers/google/llm/gemini-pro.yaml diff --git a/api/core/model_runtime/model_providers/google/google.py b/api/core/model_runtime/model_providers/google/google.py index 70f56a8337..88ea50ea2b 100644 --- a/api/core/model_runtime/model_providers/google/google.py +++ b/api/core/model_runtime/model_providers/google/google.py @@ -19,8 +19,8 @@ class GoogleProvider(ModelProvider): try: model_instance = self.get_model_instance(ModelType.LLM) - # Use `gemini-pro` model for validate, - model_instance.validate_credentials(model="gemini-pro", credentials=credentials) + # Use `gemini-2.0-flash` model for validate, + model_instance.validate_credentials(model="gemini-2.0-flash", credentials=credentials) except CredentialsValidateFailedError as ex: raise ex except Exception as ex: diff --git a/api/core/model_runtime/model_providers/google/llm/_position.yaml b/api/core/model_runtime/model_providers/google/llm/_position.yaml index 07ede384b0..4c7c4151f1 100644 --- a/api/core/model_runtime/model_providers/google/llm/_position.yaml +++ b/api/core/model_runtime/model_providers/google/llm/_position.yaml @@ -19,5 +19,3 @@ - gemini-exp-1206 - gemini-exp-1121 - gemini-exp-1114 -- gemini-pro -- gemini-pro-vision diff --git a/api/core/model_runtime/model_providers/google/llm/gemini-pro-vision.yaml b/api/core/model_runtime/model_providers/google/llm/gemini-pro-vision.yaml deleted file mode 100644 index 5b589745d7..0000000000 --- a/api/core/model_runtime/model_providers/google/llm/gemini-pro-vision.yaml +++ /dev/null @@ -1,35 +0,0 @@ -model: gemini-pro-vision -label: - en_US: Gemini Pro Vision -model_type: llm -features: - - vision -model_properties: - mode: chat - context_size: 12288 -parameter_rules: - - name: temperature - use_template: temperature - - name: top_p - use_template: top_p - - name: top_k - label: - zh_Hans: 取样数量 - en_US: Top k - type: int - help: - zh_Hans: 仅从每个后续标记的前 K 个选项中采样。 - en_US: Only sample from the top K options for each subsequent token. - required: false - - name: max_tokens_to_sample - use_template: max_tokens - required: true - default: 4096 - min: 1 - max: 4096 -pricing: - input: '0.00' - output: '0.00' - unit: '0.000001' - currency: USD -deprecated: true diff --git a/api/core/model_runtime/model_providers/google/llm/gemini-pro.yaml b/api/core/model_runtime/model_providers/google/llm/gemini-pro.yaml deleted file mode 100644 index f05fec8c5d..0000000000 --- a/api/core/model_runtime/model_providers/google/llm/gemini-pro.yaml +++ /dev/null @@ -1,39 +0,0 @@ -model: gemini-pro -label: - en_US: Gemini Pro -model_type: llm -features: - - agent-thought - - tool-call - - stream-tool-call -model_properties: - mode: chat - context_size: 30720 -parameter_rules: - - name: temperature - use_template: temperature - - name: top_p - use_template: top_p - - name: top_k - label: - zh_Hans: 取样数量 - en_US: Top k - type: int - help: - zh_Hans: 仅从每个后续标记的前 K 个选项中采样。 - en_US: Only sample from the top K options for each subsequent token. - required: false - - name: max_tokens_to_sample - use_template: max_tokens - required: true - default: 2048 - min: 1 - max: 2048 - - name: response_format - use_template: response_format -pricing: - input: '0.00' - output: '0.00' - unit: '0.000001' - currency: USD -deprecated: true From 99a9def623ca547bcdb2e6f24c3f0768083ae1b4 Mon Sep 17 00:00:00 2001 From: Xiyuan Chen <52963600+GareArc@users.noreply.github.com> Date: Fri, 18 Apr 2025 05:04:44 -0400 Subject: [PATCH 4/9] fix: reset_password security issue (#18366) --- .../console/auth/forgot_password.py | 26 ++++++++++++++++--- api/controllers/console/auth/login.py | 4 ++- api/controllers/console/wraps.py | 16 +++++++++++- api/services/account_service.py | 22 +++++++++++++--- 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/api/controllers/console/auth/forgot_password.py b/api/controllers/console/auth/forgot_password.py index a9c4300b9a..2ee9c7c468 100644 --- a/api/controllers/console/auth/forgot_password.py +++ b/api/controllers/console/auth/forgot_password.py @@ -6,9 +6,13 @@ from flask_restful import Resource, reqparse # type: ignore from constants.languages import languages from controllers.console import api -from controllers.console.auth.error import EmailCodeError, InvalidEmailError, InvalidTokenError, PasswordMismatchError -from controllers.console.error import AccountInFreezeError, AccountNotFound, EmailSendIpLimitError -from controllers.console.wraps import setup_required +from controllers.console.auth.error import (EmailCodeError, InvalidEmailError, + InvalidTokenError, + PasswordMismatchError) +from controllers.console.error import (AccountInFreezeError, AccountNotFound, + EmailSendIpLimitError) +from controllers.console.wraps import (email_password_login_enabled, + setup_required) from events.tenant_event import tenant_was_created from extensions.ext_database import db from libs.helper import email, extract_remote_ip @@ -22,6 +26,7 @@ from services.feature_service import FeatureService class ForgotPasswordSendEmailApi(Resource): @setup_required + @email_password_login_enabled def post(self): parser = reqparse.RequestParser() parser.add_argument("email", type=email, required=True, location="json") @@ -53,6 +58,7 @@ class ForgotPasswordSendEmailApi(Resource): class ForgotPasswordCheckApi(Resource): @setup_required + @email_password_login_enabled def post(self): parser = reqparse.RequestParser() parser.add_argument("email", type=str, required=True, location="json") @@ -72,11 +78,20 @@ class ForgotPasswordCheckApi(Resource): if args["code"] != token_data.get("code"): raise EmailCodeError() - return {"is_valid": True, "email": token_data.get("email")} + # Verified, revoke the first token + AccountService.revoke_reset_password_token(args["token"]) + + # Refresh token data by generating a new token + _, new_token = AccountService.generate_reset_password_token( + user_email, code=args["code"], additional_data={"phase": "reset"} + ) + + return {"is_valid": True, "email": token_data.get("email"), "token": new_token} class ForgotPasswordResetApi(Resource): @setup_required + @email_password_login_enabled def post(self): parser = reqparse.RequestParser() parser.add_argument("token", type=str, required=True, nullable=False, location="json") @@ -95,6 +110,9 @@ class ForgotPasswordResetApi(Resource): if reset_data is None: raise InvalidTokenError() + # Must use token in reset phase + if reset_data.get("phase", "") != "reset": + raise InvalidTokenError() AccountService.revoke_reset_password_token(token) diff --git a/api/controllers/console/auth/login.py b/api/controllers/console/auth/login.py index 41362e9fa2..16c1dcc441 100644 --- a/api/controllers/console/auth/login.py +++ b/api/controllers/console/auth/login.py @@ -22,7 +22,7 @@ from controllers.console.error import ( EmailSendIpLimitError, NotAllowedCreateWorkspace, ) -from controllers.console.wraps import setup_required +from controllers.console.wraps import email_password_login_enabled, setup_required from events.tenant_event import tenant_was_created from libs.helper import email, extract_remote_ip from libs.password import valid_password @@ -38,6 +38,7 @@ class LoginApi(Resource): """Resource for user login.""" @setup_required + @email_password_login_enabled def post(self): """Authenticate user and login.""" parser = reqparse.RequestParser() @@ -110,6 +111,7 @@ class LogoutApi(Resource): class ResetPasswordSendEmailApi(Resource): @setup_required + @email_password_login_enabled def post(self): parser = reqparse.RequestParser() parser.add_argument("email", type=email, required=True, location="json") diff --git a/api/controllers/console/wraps.py b/api/controllers/console/wraps.py index 111db7ccf2..71567e3afe 100644 --- a/api/controllers/console/wraps.py +++ b/api/controllers/console/wraps.py @@ -11,7 +11,8 @@ from models.model import DifySetup from services.feature_service import FeatureService, LicenseStatus from services.operation_service import OperationService -from .error import NotInitValidateError, NotSetupError, UnauthorizedAndForceLogout +from .error import (NotInitValidateError, NotSetupError, + UnauthorizedAndForceLogout) def account_initialization_required(view): @@ -154,3 +155,16 @@ def enterprise_license_required(view): return view(*args, **kwargs) return decorated + + +def email_password_login_enabled(view): + @wraps(view) + def decorated(*args, **kwargs): + features = FeatureService.get_system_features() + if features.enable_email_password_login: + return view(*args, **kwargs) + + # otherwise, return 403 + abort(403) + + return decorated diff --git a/api/services/account_service.py b/api/services/account_service.py index dd1cc5f94f..2fbc446984 100644 --- a/api/services/account_service.py +++ b/api/services/account_service.py @@ -406,10 +406,8 @@ class AccountService: raise PasswordResetRateLimitExceededError() - code = "".join([str(random.randint(0, 9)) for _ in range(6)]) - token = TokenManager.generate_token( - account=account, email=email, token_type="reset_password", additional_data={"code": code} - ) + code, token = cls.generate_reset_password_token(account_email, account) + send_reset_password_mail_task.delay( language=language, to=account_email, @@ -418,6 +416,22 @@ class AccountService: cls.reset_password_rate_limiter.increment_rate_limit(account_email) return token + @classmethod + def generate_reset_password_token( + cls, + email: str, + account: Optional[Account] = None, + code: Optional[str] = None, + additional_data: dict[str, Any] = {}, + ): + if not code: + code = "".join([str(random.randint(0, 9)) for _ in range(6)]) + additional_data["code"] = code + token = TokenManager.generate_token( + account=account, email=email, token_type="reset_password", additional_data=additional_data + ) + return code, token + @classmethod def revoke_reset_password_token(cls, token: str): TokenManager.revoke_token(token, "reset_password") From 161ff432f1d47ed0e1b7379cd8d2dfee81b87fc5 Mon Sep 17 00:00:00 2001 From: NFish Date: Fri, 18 Apr 2025 17:15:15 +0800 Subject: [PATCH 5/9] fix: update reset password token when email code verify success (#18362) --- web/app/reset-password/check-code/page.tsx | 6 +++++- web/service/common.ts | 14 +++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/web/app/reset-password/check-code/page.tsx b/web/app/reset-password/check-code/page.tsx index ca53b68750..b8cb87629b 100644 --- a/web/app/reset-password/check-code/page.tsx +++ b/web/app/reset-password/check-code/page.tsx @@ -39,7 +39,11 @@ export default function CheckCode() { } setIsLoading(true) const ret = await verifyResetPasswordCode({ email, code, token }) - ret.is_valid && router.push(`/reset-password/set-password?${searchParams.toString()}`) + if (ret.is_valid) { + const params = new URLSearchParams(searchParams) + params.set('token', encodeURIComponent(ret.token)) + router.push(`/reset-password/set-password?${params.toString()}`) + } } catch (error) { console.error(error) } finally { diff --git a/web/service/common.ts b/web/service/common.ts index 5910965ec2..06562ece0c 100644 --- a/web/service/common.ts +++ b/web/service/common.ts @@ -40,7 +40,7 @@ import type { SystemFeatures } from '@/types/feature' type LoginSuccess = { result: 'success' - data: { access_token: string;refresh_token: string } + data: { access_token: string; refresh_token: string } } type LoginFail = { result: 'fail' @@ -331,20 +331,20 @@ export const uploadRemoteFileInfo = (url: string, isPublic?: boolean) => { export const sendEMailLoginCode = (email: string, language = 'en-US') => post('/email-code-login', { body: { email, language } }) -export const emailLoginWithCode = (data: { email: string;code: string;token: string }) => +export const emailLoginWithCode = (data: { email: string; code: string; token: string }) => post('/email-code-login/validity', { body: data }) export const sendResetPasswordCode = (email: string, language = 'en-US') => - post('/forgot-password', { body: { email, language } }) + post('/forgot-password', { body: { email, language } }) -export const verifyResetPasswordCode = (body: { email: string;code: string;token: string }) => - post('/forgot-password/validity', { body }) +export const verifyResetPasswordCode = (body: { email: string; code: string; token: string }) => + post('/forgot-password/validity', { body }) export const sendDeleteAccountCode = () => get('/account/delete/verify') -export const verifyDeleteAccountCode = (body: { code: string;token: string }) => +export const verifyDeleteAccountCode = (body: { code: string; token: string }) => post('/account/delete', { body }) -export const submitDeleteAccountFeedback = (body: { feedback: string;email: string }) => +export const submitDeleteAccountFeedback = (body: { feedback: string; email: string }) => post('/account/delete/feedback', { body }) From b26e20fe342548a75e6da8bff1fa9f4211596062 Mon Sep 17 00:00:00 2001 From: kautsar_masuara <61046989+izon-masuara@users.noreply.github.com> Date: Sat, 19 Apr 2025 22:04:13 +0800 Subject: [PATCH 6/9] fix: fix vertex gemini 2.0 flash 001 schema (#18405) Co-authored-by: achmad-kautsar --- .../vertex_ai/llm/gemini-2.0-flash-001.yaml | 14 ++--- web/app/components/base/chat/utils.ts | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/api/core/model_runtime/model_providers/vertex_ai/llm/gemini-2.0-flash-001.yaml b/api/core/model_runtime/model_providers/vertex_ai/llm/gemini-2.0-flash-001.yaml index bef7ca5eef..494f5aa68e 100644 --- a/api/core/model_runtime/model_providers/vertex_ai/llm/gemini-2.0-flash-001.yaml +++ b/api/core/model_runtime/model_providers/vertex_ai/llm/gemini-2.0-flash-001.yaml @@ -5,11 +5,6 @@ model_type: llm features: - agent-thought - vision - - tool-call - - stream-tool-call - - document - - video - - audio model_properties: mode: chat context_size: 1048576 @@ -20,20 +15,21 @@ parameter_rules: use_template: top_p - name: top_k label: - zh_Hans: 取样数量 en_US: Top k type: int help: - zh_Hans: 仅从每个后续标记的前 K 个选项中采样。 en_US: Only sample from the top K options for each subsequent token. required: false + - name: presence_penalty + use_template: presence_penalty + - name: frequency_penalty + use_template: frequency_penalty - name: max_output_tokens use_template: max_tokens + required: true default: 8192 min: 1 max: 8192 - - name: json_schema - use_template: json_schema pricing: input: '0.00' output: '0.00' diff --git a/web/app/components/base/chat/utils.ts b/web/app/components/base/chat/utils.ts index ce7a7c09b3..4539e88d0e 100644 --- a/web/app/components/base/chat/utils.ts +++ b/web/app/components/base/chat/utils.ts @@ -1,6 +1,8 @@ import { UUID_NIL } from './constants' import type { IChatItem } from './chat/type' import type { ChatItem, ChatItemInTree } from './types' +import { addFileInfos, sortAgentSorts } from '../../tools/utils' +import { getProcessedFilesFromResponse } from '../file-uploader/utils' async function decodeBase64AndDecompress(base64String: string) { const binaryString = atob(base64String) @@ -19,6 +21,60 @@ function getProcessedInputsFromUrlParams(): Record { return inputs } +function appendQAToChatList(chatList: ChatItem[], item: any) { + // we append answer first and then question since will reverse the whole chatList later + const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [] + chatList.push({ + id: item.id, + content: item.answer, + agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files), + feedback: item.feedback, + isAnswer: true, + citation: item.retriever_resources, + message_files: getProcessedFilesFromResponse(answerFiles.map((item: any) => ({ ...item, related_id: item.id }))), + }) + const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || [] + chatList.push({ + id: `question-${item.id}`, + content: item.query, + isAnswer: false, + message_files: getProcessedFilesFromResponse(questionFiles.map((item: any) => ({ ...item, related_id: item.id }))), + }) +} + +/** + * Computes the latest thread messages from all messages of the conversation. + * Same logic as backend codebase `api/core/prompt/utils/extract_thread_messages.py` + * + * @param fetchedMessages - The history chat list data from the backend, sorted by created_at in descending order. This includes all flattened history messages of the conversation. + * @returns An array of ChatItems representing the latest thread. + */ + + +function getPrevChatList(fetchedMessages: any[]) { + const ret: ChatItem[] = [] + let nextMessageId = null + + for (const item of fetchedMessages) { + if (!item.parent_message_id) { + appendQAToChatList(ret, item) + break + } + + if (!nextMessageId) { + appendQAToChatList(ret, item) + nextMessageId = item.parent_message_id + } + else { + if (item.id === nextMessageId || nextMessageId === UUID_NIL) { + appendQAToChatList(ret, item) + nextMessageId = item.parent_message_id + } + } + } + return ret.reverse() +} + function isValidGeneratedAnswer(item?: ChatItem | ChatItemInTree): boolean { return !!item && item.isAnswer && !item.id.startsWith('answer-placeholder-') && !item.isOpeningStatement } @@ -164,6 +220,7 @@ function getThreadMessages(tree: ChatItemInTree[], targetMessageId?: string): Ch export { getProcessedInputsFromUrlParams, isValidGeneratedAnswer, + getPrevChatList, getLastAnswer, buildChatItemTree, getThreadMessages, From a1b3d41712374a4330b6d047d2ab3c5f2b14c790 Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 22 Apr 2025 17:08:52 +0800 Subject: [PATCH 7/9] fix: clickjacking (#18552) --- api/.env.example | 5 +++- docker/.env.example | 3 ++ docker/docker-compose-template.yaml | 3 +- docker/docker-compose.yaml | 2 ++ web/.env.example | 3 ++ .../app/overview/embedded/index.tsx | 10 +++---- web/docker/entrypoint.sh | 1 + web/middleware.ts | 28 +++++++++++++------ 8 files changed, 39 insertions(+), 16 deletions(-) diff --git a/api/.env.example b/api/.env.example index 95da531a1d..4f973737c9 100644 --- a/api/.env.example +++ b/api/.env.example @@ -430,4 +430,7 @@ CREATE_TIDB_SERVICE_JOB_ENABLED=false # Maximum number of submitted thread count in a ThreadPool for parallel node execution MAX_SUBMIT_COUNT=100 # Lockout duration in seconds -LOGIN_LOCKOUT_DURATION=86400 \ No newline at end of file +LOGIN_LOCKOUT_DURATION=86400 + +# Prevent Clickjacking +ALLOW_EMBED=false \ No newline at end of file diff --git a/docker/.env.example b/docker/.env.example index b21bdc7085..0faf9a337d 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -932,3 +932,6 @@ MAX_SUBMIT_COUNT=100 # The maximum number of top-k value for RAG. TOP_K_MAX_VALUE=10 + +# Prevent Clickjacking +ALLOW_EMBED=false \ No newline at end of file diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index 9f1cb3d741..6c48aaf87c 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -1,4 +1,4 @@ -x-shared-env: &shared-api-worker-env +x-shared-env: &shared-api-worker-env services: # API service api: @@ -56,6 +56,7 @@ services: NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0} TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000} CSP_WHITELIST: ${CSP_WHITELIST:-} + ALLOW_EMBED: ${ALLOW_EMBED:-false} TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-} INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-} diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index cece2af76d..bef04e2e59 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -389,6 +389,7 @@ x-shared-env: &shared-api-worker-env CREATE_TIDB_SERVICE_JOB_ENABLED: ${CREATE_TIDB_SERVICE_JOB_ENABLED:-false} MAX_SUBMIT_COUNT: ${MAX_SUBMIT_COUNT:-100} TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-10} + ALLOW_EMBED: ${ALLOW_EMBED:-false} services: # API service @@ -447,6 +448,7 @@ services: NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0} TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000} CSP_WHITELIST: ${CSP_WHITELIST:-} + ALLOW_EMBED: ${ALLOW_EMBED:-false} TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-} INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-} diff --git a/web/.env.example b/web/.env.example index e2117ddfd8..7ddf600624 100644 --- a/web/.env.example +++ b/web/.env.example @@ -31,3 +31,6 @@ NEXT_PUBLIC_TOP_K_MAX_VALUE=10 # The maximum number of tokens for segmentation NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=4000 + +# Default is not allow to embed into iframe to prevent Clickjacking: https://owasp.org/www-community/attacks/Clickjacking +NEXT_PUBLIC_ALLOW_EMBED= diff --git a/web/app/components/app/overview/embedded/index.tsx b/web/app/components/app/overview/embedded/index.tsx index b71a3c3fdf..5d363b421a 100644 --- a/web/app/components/app/overview/embedded/index.tsx +++ b/web/app/components/app/overview/embedded/index.tsx @@ -24,7 +24,7 @@ const OPTION_MAP = { iframe: { getContent: (url: string, token: string) => `