Skip to content
Open
8 changes: 7 additions & 1 deletion packages/amis-editor-core/src/locale/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,5 +287,11 @@ extendLocale('en-US', {
'0383d6f467ed0dd89860a7b8cc793ce9': 'Upper {{@1}} layer {{@2}}',
'b818d2fd22f70de2d912f19048e2cde2': 'Intercepted {{@1}} rendering error',
'e9a11b908a9b4f3d9dc947d9a64c0dab':
'A rendering error occurred. Please refer to the console output for detailed error information.'
'A rendering error occurred. Please refer to the console output for detailed error information.',
'f407c6b6264be4b590e28085d392b73d':
'It can be dragged into the following area to fix the drag-and-drop container',
'4d681c4aa93c8d005ec2ca2370618d6e': 'Visible',
'dce5379cb978a8259ecfca8f08f00817': 'Hide',
'02cc4f8f5a9aefbc03c778f7a5c989c7': 'Enter',
'35ba83e053cef95e55dfffde279822b5': 'No data displayed'
});
7 changes: 6 additions & 1 deletion packages/amis-editor-core/src/locale/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,5 +259,10 @@ extendLocale('zh-CN', {
'0383d6f467ed0dd89860a7b8cc793ce9': '上{{@1}}层{{@2}}',
'b818d2fd22f70de2d912f19048e2cde2': '拦截到{{@1}}渲染错误',
'e9a11b908a9b4f3d9dc947d9a64c0dab':
'渲染发生错误,详细错误信息请查看控制台输出。'
'渲染发生错误,详细错误信息请查看控制台输出。',
'f407c6b6264be4b590e28085d392b73d': '可拖入以下区域固定拖入容器',
'4d681c4aa93c8d005ec2ca2370618d6e': '可见',
'dce5379cb978a8259ecfca8f08f00817': '隐藏',
'02cc4f8f5a9aefbc03c778f7a5c989c7': '请输入',
'35ba83e053cef95e55dfffde279822b5': '无数据提示'
});
696 changes: 695 additions & 1 deletion packages/amis-editor/src/locale/en-US.ts

Large diffs are not rendered by default.

649 changes: 648 additions & 1 deletion packages/amis-editor/src/locale/zh-CN.ts

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions packages/amis-editor/src/renderer/textarea-formula/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import {TextareaFormulaControlProps} from './TextareaFormulaControl';
import {FormulaEditor} from 'amis-ui';
import {escapeHtml} from 'amis-core';
import type {VariableItem, CodeMirror} from 'amis-ui';

export function editorFactory(
Expand Down Expand Up @@ -226,20 +227,23 @@ export class FormulaPlugin {
this.config;

const variables = getProps()?.variables as VariableItem[];
// 获取用户传入的 filterHtml,用于 XSS 过滤
const filterHtml = getProps()?.env?.filterHtml || ((html: string) => html);
const highlightValue = FormulaEditor.highlightValue(
expression,
variables,
true,
false
) || {
html: expression
html: escapeHtml(expression)
};

const wrap = document.createElement('span');
wrap.className = className;
const text = document.createElement('span');
text.className = `${className}-text`;
text.innerHTML = highlightValue.html;
// 使用 filterHtml 进行 XSS 过滤
text.innerHTML = filterHtml(highlightValue.html);
text.setAttribute('data-expression', expression);
text.onmouseenter = e => {
const brace = this.getExpressionBrace(expression);
Expand All @@ -260,8 +264,8 @@ export class FormulaPlugin {
if (showPopover) {
// 添加popover
const popoverEl = document.createElement('div');
// bca-disable-next-line
popoverEl.innerHTML = highlightValue.html;
// 使用 filterHtml 进行 XSS 过滤
popoverEl.innerHTML = filterHtml(highlightValue.html);
popoverEl.classList.add('cm-expression-popover');
const arrow = document.createElement('div');
arrow.classList.add('cm-expression-popover-arrow');
Expand Down
3 changes: 0 additions & 3 deletions packages/amis-theme-editor-helper/i18nConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ module.exports = {
test: /.*(ts|tsx|js|jsx)$/
},
includes: ['src/renderers'],
ignore: {
list: ['src/*']
},
importInfo: {
source: 'i18n-runtime',
imported: 'i18n',
Expand Down
15 changes: 14 additions & 1 deletion packages/amis-theme-editor-helper/src/locale/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,5 +229,18 @@ extendLocale('en-US', {
'c0215e2abf0fe27597acba2be64f6993': 'Small size',
'93dee976f68681ec6950380d757d8c18': 'Multiple selection mode',
'9be232c5cffa019aab21bd631ff23462': 'Yunshe',
'1dfba2e7e2df2efc4a25f4f2adcba25e': 'System preset theme'
'1dfba2e7e2df2efc4a25f4f2adcba25e': 'System preset theme',
'96b15b89fd7df6180780a7ac7305ba7c': 'Border size',
'84fafbb9668c30ba550e8bd3ebab65a6': 'Border style',
'9b4bae5d8251de0b6f00b704936b00d3': 'Border color',
'd9c2ace0d7ecc55bdea2fd91732ca29c': 'Gradient',
'20def7942674282277c3714ed7ea6ce0': 'image',
'690660d9dbd7312ad2825e554736e2f8': 'Font color',
'5f15efdc32badce0902c46a7a0105c51': 'Font size',
'916e646c9e6add3ae7053cbec7c37d91': 'Font weight',
'c3ce3c8fd80b9b9e221353faa162facf': 'Line height',
'4e7f76261f8c4c6d78998f85fc1f4c6e': 'Margin',
'841d77223f0ec8cd0b530ed8e0775b20': 'Padding',
'border-size': 'Border size',
'border-style': 'Border style'
});
15 changes: 14 additions & 1 deletion packages/amis-theme-editor-helper/src/locale/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,5 +228,18 @@ extendLocale('zh-CN', {
'c0215e2abf0fe27597acba2be64f6993': '尺寸小',
'93dee976f68681ec6950380d757d8c18': '多选模式',
'9be232c5cffa019aab21bd631ff23462': '云舍',
'1dfba2e7e2df2efc4a25f4f2adcba25e': '系统预设主题'
'1dfba2e7e2df2efc4a25f4f2adcba25e': '系统预设主题',
'96b15b89fd7df6180780a7ac7305ba7c': '边框粗细',
'84fafbb9668c30ba550e8bd3ebab65a6': '边框样式',
'9b4bae5d8251de0b6f00b704936b00d3': '边框颜色',
'd9c2ace0d7ecc55bdea2fd91732ca29c': '渐变',
'20def7942674282277c3714ed7ea6ce0': '图片',
'690660d9dbd7312ad2825e554736e2f8': '字体颜色',
'5f15efdc32badce0902c46a7a0105c51': '字体大小',
'916e646c9e6add3ae7053cbec7c37d91': '字体字重',
'c3ce3c8fd80b9b9e221353faa162facf': '字体行高',
'4e7f76261f8c4c6d78998f85fc1f4c6e': '外边距',
'841d77223f0ec8cd0b530ed8e0775b20': '内边距',
'border-size': '边框粗细',
'border-style': '边框样式'
});
6 changes: 4 additions & 2 deletions packages/amis-theme-editor-helper/src/renderers/Border.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,9 @@ function BoxBorder(props: BorderProps & FormControlProps) {
borderType === 'all' ? 'top' : borderType
}-border-width`}
state={state}
placeholder={editorDefaultValue?.[getKey('width')] || '边框粗细'}
placeholder={
editorDefaultValue?.[getKey('width')] || _i18n('border-size')
}
/>
<div className="Theme-Border-settings-style-color">
<Select
Expand All @@ -291,7 +293,7 @@ function BoxBorder(props: BorderProps & FormControlProps) {
getLabel(
editorDefaultValue?.[getKey('style')],
borderStyleOptions
) || '边框样式'
) || _i18n('border-style')
}
onChange={(item: any) => changeItem('style')(item.value)}
clearable={!!editorDefaultValue}
Expand Down
8 changes: 7 additions & 1 deletion packages/amis-ui/src/components/Html.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ export interface HtmlProps {
filterHtml?: (input: string) => string;
}

export const HTMLFilterContext = React.createContext((txt: string) => txt);

export class Html extends React.Component<HtmlProps> {
static defaultProps = {
inline: true
};

dom: any;

static contextType = HTMLFilterContext;

constructor(props: HtmlProps) {
super(props);
this.htmlRef = this.htmlRef.bind(this);
Expand All @@ -49,7 +53,9 @@ export class Html extends React.Component<HtmlProps> {
const {html, filterHtml} = this.props;

if (html) {
this.dom.innerHTML = filterHtml ? filterHtml(html) : html;
let filter: (text: string) => string =
filterHtml || (this.context as any) || ((text: string) => text);
this.dom.innerHTML = filter(html);
}
}

Expand Down
8 changes: 2 additions & 6 deletions packages/amis-ui/src/components/TooltipWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,7 @@ export class TooltipWrapper extends React.Component<
offset,
tooltipTheme = 'light',
showArrow = true,
children,
filterHtml
children
} = tooltipObj;

const childProps: any = {
Expand Down Expand Up @@ -372,10 +371,7 @@ export class TooltipWrapper extends React.Component<
{children ? (
<>{typeof children === 'function' ? children() : children}</>
) : (
<Html
html={typeof content === 'string' ? content : ''}
filterHtml={filterHtml}
/>
<Html html={typeof content === 'string' ? content : ''} />
)}
</Tooltip>
</Overlay>
Expand Down
6 changes: 4 additions & 2 deletions packages/amis-ui/src/components/formula/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import React from 'react';
import {
eachTree,
resolveVariableAndFilterForAsync,
uncontrollable
uncontrollable,
escapeHtml
} from 'amis-core';
import {
parse,
Expand Down Expand Up @@ -208,7 +209,8 @@ export class FormulaEditor extends React.Component<
.filter(item => item)
.sort((a, b) => b.length - a.length);

const content = value || '';
// XSS 防护:对用户输入进行转义
const content = escapeHtml(value || '');
let html = '';

// 标记方法调用
Expand Down
4 changes: 3 additions & 1 deletion packages/amis-ui/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import type {SchemaEditorItemPlaceholder} from './components/schema-editor/Commo
import {schemaEditorItemPlaceholder} from './components/schema-editor/Common';
import withStore from './withStore';
import withRemoteConfig from './withRemoteConfig';
import {HTMLFilterContext} from './components/Html';

export {
schemaEditorItemPlaceholder,
SchemaEditorItemPlaceholder,
withStore,
withRemoteConfig
withRemoteConfig,
HTMLFilterContext
};
10 changes: 6 additions & 4 deletions packages/amis/src/preset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
themeable,
ThemeProps
} from 'amis-core';
import {ImageGallery} from 'amis-ui';
import {HTMLFilterContext, ImageGallery} from 'amis-ui';
import {setRenderSchemaFn} from 'amis-ui/lib/components/Alert';
import {alert, confirm} from 'amis-ui/lib/components/Alert';
import {toast} from 'amis-ui/lib/components/Toast';
Expand Down Expand Up @@ -46,9 +46,11 @@ setRenderSchemaFn((controls, value, callback, scopeRef, theme) => {
addRootWrapper((props: any) => {
const {env, children} = props;
return (
<ImageGallery modalContainer={env.getModalContainer}>
{children}
</ImageGallery>
<HTMLFilterContext.Provider value={env.filterHtml}>
<ImageGallery modalContainer={env.getModalContainer}>
{children}
</ImageGallery>
</HTMLFilterContext.Provider>
);
});

Expand Down
6 changes: 1 addition & 5 deletions packages/amis/src/renderers/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -337,11 +337,7 @@ export class App extends React.Component<AppProps, object> {

<div className={cx('Layout-brand')}>
{logo && ~logo.indexOf('<svg') ? (
<Html
className={cx('AppLogo-html')}
html={logo}
filterHtml={env.filterHtml}
/>
<Html className={cx('AppLogo-html')} html={logo} />
) : logo ? (
<img className={cx('AppLogo')} src={logo} />
) : (
Expand Down
2 changes: 1 addition & 1 deletion packages/amis/src/renderers/CRUD.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2763,7 +2763,7 @@ export default class CRUD<T extends CRUDProps> extends React.Component<T, any> {
</span>
<span className={cx('Crud-valueLabel')}>
{labelTpl ? (
<Html html={filter(labelTpl, item)} filterHtml={env.filterHtml} />
<Html html={filter(labelTpl, item)} />
) : (
getVariable(item, labelField || 'label') ||
getVariable(item, valueField || primaryField || 'id')
Expand Down
5 changes: 1 addition & 4 deletions packages/amis/src/renderers/CRUD2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1424,10 +1424,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
</span>
<span className={cx('Crud-valueLabel')}>
{labelTpl ? (
<Html
html={filter(labelTpl, item)}
filterHtml={env.filterHtml}
/>
<Html html={filter(labelTpl, item)} />
) : (
getVariable(item, labelField || 'label') ||
getVariable(item, primaryField || 'id')
Expand Down
2 changes: 1 addition & 1 deletion packages/amis/src/renderers/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ const defaultSchema = {
className={cx('Carousel-image')}
/>
) : data.hasOwnProperty('html') ? (
<Html html={data.html} filterHtml={props.env.filterHtml} />
<Html html={data.html} />
) : data.hasOwnProperty('item') ? (
<span>{data.item}</span>
) : (
Expand Down
2 changes: 1 addition & 1 deletion packages/amis/src/renderers/Form/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ export default class PickerControl extends React.PureComponent<
}}
>
{labelTpl ? (
<Html html={filter(labelTpl, item)} filterHtml={env.filterHtml} />
<Html html={filter(labelTpl, item)} />
) : (
`${
getVariable(item, labelField || 'label') ||
Expand Down
5 changes: 3 additions & 2 deletions packages/amis/src/renderers/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ export class LinkCmpt extends React.Component<LinkProps, object> {
translate: __,
title,
icon,
rightIcon
rightIcon,
env
} = this.props;

let value =
Expand All @@ -106,7 +107,7 @@ export class LinkCmpt extends React.Component<LinkProps, object> {
<Link
className={className}
style={style}
href={value}
href={env.filterHtml(value)}
disabled={disabled}
title={title}
htmlTarget={htmlTarget || (blank ? '_blank' : '_self')}
Expand Down