Commit e6de4950 by siigure Committed by GitHub

Codex/siigure http https (#7085)

* feat: support workflow HTTP HTTPS cert ignore config

* revert

---------

Co-authored-by: archer <545436317@qq.com>
parent 89225d79
...@@ -166,6 +166,10 @@ export type SystemEnvType = { ...@@ -166,6 +166,10 @@ export type SystemEnvType = {
customPdfParse?: customPdfParseType; customPdfParse?: customPdfParseType;
fileUrlWhitelist?: string[]; fileUrlWhitelist?: string[];
customDomain?: customDomainType; customDomain?: customDomainType;
workflowHttpNode?: {
/** 是否允许工作流 HTTP 节点忽略 HTTPS 证书校验。 */
ignoreHttpsCertificate?: boolean;
};
}; };
export type customDomainType = { export type customDomainType = {
......
import _, { type AxiosInstance, type AxiosRequestConfig } from 'axios'; import _, { type AxiosInstance, type AxiosRequestConfig } from 'axios';
import { ProxyAgent } from 'proxy-agent'; import { ProxyAgent, type ProxyAgentOptions } from 'proxy-agent';
import { isDevEnv } from '@fastgpt/global/common/system/constants'; import { isDevEnv } from '@fastgpt/global/common/system/constants';
import { isInternalAddress, PRIVATE_URL_TEXT } from '../system/utils'; import { isInternalAddress, PRIVATE_URL_TEXT } from '../system/utils';
import { isAbsoluteUrl } from '../security/network'; import { isAbsoluteUrl } from '../security/network';
...@@ -26,8 +26,18 @@ const addSSRFInterceptor = (instance: AxiosInstance) => { ...@@ -26,8 +26,18 @@ const addSSRFInterceptor = (instance: AxiosInstance) => {
return instance; return instance;
}; };
const createProxyAgent = (options?: ProxyAgentOptions) => new ProxyAgent(options);
/**
* 工作流 HTTP 节点跳过 HTTPS 证书校验专用 agent。
* 仍复用 ProxyAgent,只调整目标站 TLS 校验策略,避免改变部署环境的代理语义。
*/
export const httpsCertificateIgnoreAgent = createProxyAgent({
rejectUnauthorized: false
});
export function createProxyAxios(config?: AxiosRequestConfig, ssrfCheck = true) { export function createProxyAxios(config?: AxiosRequestConfig, ssrfCheck = true) {
const agent = new ProxyAgent(); const agent = createProxyAgent();
const instance = isDevEnv const instance = isDevEnv
? _.create(config) ? _.create(config)
......
...@@ -20,6 +20,7 @@ export const getFastGPTConfigFromDB = async (): Promise<{ ...@@ -20,6 +20,7 @@ export const getFastGPTConfigFromDB = async (): Promise<{
}).sort({ }).sort({
createTime: -1 createTime: -1
}), }),
MongoSystemConfigs.findOne({ MongoSystemConfigs.findOne({
type: SystemConfigsTypeEnum.license type: SystemConfigsTypeEnum.license
}).sort({ }).sort({
......
...@@ -19,6 +19,7 @@ import { ...@@ -19,6 +19,7 @@ import {
replaceEditorVariable, replaceEditorVariable,
valueTypeFormat valueTypeFormat
} from '@fastgpt/global/core/workflow/runtime/utils'; } from '@fastgpt/global/core/workflow/runtime/utils';
import type { AxiosRequestConfig } from 'axios';
import json5 from 'json5'; import json5 from 'json5';
import { JSONPath } from 'jsonpath-plus'; import { JSONPath } from 'jsonpath-plus';
import { getSecretValue } from '../../../../common/secret/utils'; import { getSecretValue } from '../../../../common/secret/utils';
...@@ -27,10 +28,37 @@ import { getLogger, LogCategories } from '../../../../common/logger'; ...@@ -27,10 +28,37 @@ import { getLogger, LogCategories } from '../../../../common/logger';
import { formatHttpError } from '../utils'; import { formatHttpError } from '../utils';
import { isInternalAddress, PRIVATE_URL_TEXT } from '../../../../common/system/utils'; import { isInternalAddress, PRIVATE_URL_TEXT } from '../../../../common/system/utils';
import { serviceRequestMaxContentLength } from '../../../../common/system/constants'; import { serviceRequestMaxContentLength } from '../../../../common/system/constants';
import { axios } from '../../../../common/api/axios'; import { axios, httpsCertificateIgnoreAgent } from '../../../../common/api/axios';
const logger = getLogger(LogCategories.MODULE.WORKFLOW.TOOLS); const logger = getLogger(LogCategories.MODULE.WORKFLOW.TOOLS);
/**
* 仅工作流 HTTP 节点允许按系统配置跳过 HTTPS 证书校验。
* 该配置不下沉到通用 axios,避免影响模型请求、HTTP 工具集等其它出站链路。
*/
export const getWorkflowHttpNodeHttpsAgentConfig = (
url: string
): Pick<AxiosRequestConfig, 'httpsAgent'> => {
const ignoreHttpsCertificate =
global.systemEnv?.workflowHttpNode?.ignoreHttpsCertificate === true;
if (!ignoreHttpsCertificate) {
return {};
}
try {
if (new URL(url).protocol !== 'https:') {
return {};
}
} catch {
return {};
}
return {
httpsAgent: httpsCertificateIgnoreAgent
};
};
type PropsArrType = { type PropsArrType = {
key: string; key: string;
type: string; type: string;
...@@ -268,7 +296,11 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H ...@@ -268,7 +296,11 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
Object.keys(results).length > 0 ? results : rawResponse Object.keys(results).length > 0 ? results : rawResponse
}; };
} catch (error) { } catch (error) {
logger.warn('HTTP tool request failed', { error, httpReqUrl: requestUrl }); logger.warn('HTTP tool request failed', {
error,
httpReqUrl: requestUrl,
ignoreHttpsCertificate: global.systemEnv?.workflowHttpNode?.ignoreHttpsCertificate === true
});
// @adapt // @adapt
if (node.catchError === undefined) { if (node.catchError === undefined) {
...@@ -515,7 +547,8 @@ async function fetchData({ ...@@ -515,7 +547,8 @@ async function fetchData({
}, },
timeout: timeout * 1000, timeout: timeout * 1000,
params: params, params: params,
data: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined data: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,
...getWorkflowHttpNodeHttpsAgentConfig(url)
}); });
return { return {
......
import { describe, it, expect } from 'vitest'; import { afterEach, describe, it, expect } from 'vitest';
import { replaceJsonBodyString } from '@fastgpt/service/core/workflow/dispatch/tools/http468'; import {
getWorkflowHttpNodeHttpsAgentConfig,
replaceJsonBodyString
} from '@fastgpt/service/core/workflow/dispatch/tools/http468';
import { httpsCertificateIgnoreAgent } from '@fastgpt/service/common/api/axios';
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type'; import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
describe('replaceJsonBodyString', () => { describe('replaceJsonBodyString', () => {
...@@ -640,3 +644,47 @@ describe('replaceJsonBodyString', () => { ...@@ -640,3 +644,47 @@ describe('replaceJsonBodyString', () => {
}); });
}); });
}); });
describe('getWorkflowHttpNodeHttpsAgentConfig', () => {
const originalSystemEnv = global.systemEnv;
afterEach(() => {
global.systemEnv = originalSystemEnv;
});
it('should not inject httpsAgent when ignoreHttpsCertificate is disabled', () => {
global.systemEnv = {
...originalSystemEnv,
workflowHttpNode: {
ignoreHttpsCertificate: false
}
};
expect(getWorkflowHttpNodeHttpsAgentConfig('https://example.com')).toEqual({});
});
it('should inject httpsAgent only for HTTPS requests when enabled', () => {
global.systemEnv = {
...originalSystemEnv,
workflowHttpNode: {
ignoreHttpsCertificate: true
}
};
const httpsConfig = getWorkflowHttpNodeHttpsAgentConfig('https://example.com');
expect(httpsConfig.httpsAgent).toBe(httpsCertificateIgnoreAgent);
expect(httpsConfig).not.toHaveProperty('proxy');
expect(getWorkflowHttpNodeHttpsAgentConfig('http://example.com')).toEqual({});
});
it('should ignore invalid urls and let request layer report url errors', () => {
global.systemEnv = {
...originalSystemEnv,
workflowHttpNode: {
ignoreHttpsCertificate: true
}
};
expect(getWorkflowHttpNodeHttpsAgentConfig('invalid-url')).toEqual({});
});
});
Subproject commit 6e8c027b70695879580f2f52f554d2d09e55599c Subproject commit cd209c713a0263acb08492738c2c4265d8dc37b9
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment