mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-03 23:06:36 +08:00
fix(waf): UA 检查开启后才显示匹配与屏蔽并补充说明
未开启 require_ua 时隐藏匹配/屏蔽区块;爬虫与非正常 UA 开关增加分类提示。
This commit is contained in:
@@ -5,7 +5,7 @@ import type { WAFIPGroup, WAFRuleNode } from '@/lib/services/openflare';
|
||||
|
||||
import { NodeProperties } from './node-properties';
|
||||
|
||||
it('toggles UA check switches and match mode', () => {
|
||||
it('hides match and block until UA check is enabled', () => {
|
||||
const node: WAFRuleNode = {
|
||||
id: 'ua',
|
||||
type: 'ua_check',
|
||||
@@ -20,17 +20,31 @@ it('toggles UA check switches and match mode', () => {
|
||||
},
|
||||
};
|
||||
const onChange = vi.fn();
|
||||
render(<NodeProperties node={node} ipGroups={[]} onChange={onChange} />);
|
||||
const { rerender } = render(
|
||||
<NodeProperties node={node} ipGroups={[]} onChange={onChange} />,
|
||||
);
|
||||
expect(screen.queryByLabelText('屏蔽常见爬虫 UA')).not.toBeInTheDocument();
|
||||
expect(screen.queryByLabelText('浏览器')).not.toBeInTheDocument();
|
||||
fireEvent.click(screen.getByLabelText('开启 UA 检查'));
|
||||
expect(onChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
config: expect.objectContaining({ require_ua: true }),
|
||||
}),
|
||||
);
|
||||
rerender(
|
||||
<NodeProperties
|
||||
node={{ ...node, config: { ...node.config, require_ua: true } }}
|
||||
ipGroups={[]}
|
||||
onChange={onChange}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByLabelText('屏蔽常见爬虫 UA')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('屏蔽非正常 UA')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('命中返回 false,优先级高于匹配'),
|
||||
screen.getByText(/浏览器或操作系统分类为 Bot/),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(/浏览器分类为 Bot、Other 或 Unknown/),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ function PropertyFields({
|
||||
开启 UA 检查
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
开启后如果请求头不携带 UA 返回 False
|
||||
开启后如果请求头不携带 UA 返回 False;并可配置匹配与屏蔽
|
||||
</FieldDescription>
|
||||
</div>
|
||||
<Switch
|
||||
@@ -166,104 +166,135 @@ function PropertyFields({
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className='space-y-3'>
|
||||
<p className='text-xs font-medium text-muted-foreground'>UA 匹配</p>
|
||||
<Field>
|
||||
<FieldLabel htmlFor={`${node.id}-match-mode`}>匹配模式</FieldLabel>
|
||||
<Select
|
||||
value={node.config.match_mode}
|
||||
onValueChange={(match_mode: 'and' | 'or') =>
|
||||
onChange({ ...node, config: { ...node.config, match_mode } })
|
||||
}
|
||||
>
|
||||
<SelectTrigger id={`${node.id}-match-mode`} className='w-full'>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value='or'>或(OR)</SelectItem>
|
||||
<SelectItem value='and'>且(AND)</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>
|
||||
浏览器与操作系统两侧都有选择时生效
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<MultiSelect
|
||||
id={`${node.id}-browsers`}
|
||||
label='浏览器'
|
||||
options={UA_BROWSER_OPTIONS.map((option) => ({
|
||||
value: option.value,
|
||||
label: option.label,
|
||||
searchText: `${option.label} ${option.value}`,
|
||||
}))}
|
||||
value={node.config.browsers}
|
||||
onChange={(browsers) =>
|
||||
onChange({ ...node, config: { ...node.config, browsers } })
|
||||
}
|
||||
/>
|
||||
<MultiSelect
|
||||
id={`${node.id}-os`}
|
||||
label='操作系统'
|
||||
options={UA_OS_OPTIONS.map((option) => ({
|
||||
value: option.value,
|
||||
label: option.label,
|
||||
searchText: `${option.label} ${option.value}`,
|
||||
}))}
|
||||
value={node.config.operating_systems}
|
||||
onChange={(operating_systems) =>
|
||||
onChange({
|
||||
...node,
|
||||
config: { ...node.config, operating_systems },
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className='space-y-3'>
|
||||
<div className='space-y-1'>
|
||||
<p className='text-xs font-medium text-muted-foreground'>屏蔽</p>
|
||||
<FieldDescription>命中返回 false,优先级高于匹配</FieldDescription>
|
||||
</div>
|
||||
<Field
|
||||
orientation='horizontal'
|
||||
className='items-center justify-between'
|
||||
>
|
||||
<FieldLabel htmlFor={`${node.id}-block-bots`}>
|
||||
屏蔽常见爬虫 UA
|
||||
</FieldLabel>
|
||||
<Switch
|
||||
id={`${node.id}-block-bots`}
|
||||
checked={node.config.block_common_bots}
|
||||
onCheckedChange={(block_common_bots) =>
|
||||
onChange({
|
||||
...node,
|
||||
config: { ...node.config, block_common_bots },
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
orientation='horizontal'
|
||||
className='items-center justify-between'
|
||||
>
|
||||
<FieldLabel htmlFor={`${node.id}-block-abnormal`}>
|
||||
屏蔽非正常 UA
|
||||
</FieldLabel>
|
||||
<Switch
|
||||
id={`${node.id}-block-abnormal`}
|
||||
checked={node.config.block_abnormal_ua}
|
||||
onCheckedChange={(block_abnormal_ua) =>
|
||||
onChange({
|
||||
...node,
|
||||
config: { ...node.config, block_abnormal_ua },
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
{node.config.require_ua && (
|
||||
<>
|
||||
<Separator />
|
||||
<div className='space-y-3'>
|
||||
<p className='text-xs font-medium text-muted-foreground'>
|
||||
UA 匹配
|
||||
</p>
|
||||
<Field>
|
||||
<FieldLabel htmlFor={`${node.id}-match-mode`}>
|
||||
匹配模式
|
||||
</FieldLabel>
|
||||
<Select
|
||||
value={node.config.match_mode}
|
||||
onValueChange={(match_mode: 'and' | 'or') =>
|
||||
onChange({
|
||||
...node,
|
||||
config: { ...node.config, match_mode },
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger
|
||||
id={`${node.id}-match-mode`}
|
||||
className='w-full'
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value='or'>或(OR)</SelectItem>
|
||||
<SelectItem value='and'>且(AND)</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>
|
||||
浏览器与操作系统两侧都有选择时生效
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<MultiSelect
|
||||
id={`${node.id}-browsers`}
|
||||
label='浏览器'
|
||||
options={UA_BROWSER_OPTIONS.map((option) => ({
|
||||
value: option.value,
|
||||
label: option.label,
|
||||
searchText: `${option.label} ${option.value}`,
|
||||
}))}
|
||||
value={node.config.browsers}
|
||||
onChange={(browsers) =>
|
||||
onChange({ ...node, config: { ...node.config, browsers } })
|
||||
}
|
||||
/>
|
||||
<MultiSelect
|
||||
id={`${node.id}-os`}
|
||||
label='操作系统'
|
||||
options={UA_OS_OPTIONS.map((option) => ({
|
||||
value: option.value,
|
||||
label: option.label,
|
||||
searchText: `${option.label} ${option.value}`,
|
||||
}))}
|
||||
value={node.config.operating_systems}
|
||||
onChange={(operating_systems) =>
|
||||
onChange({
|
||||
...node,
|
||||
config: { ...node.config, operating_systems },
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className='space-y-3'>
|
||||
<div className='space-y-1'>
|
||||
<p className='text-xs font-medium text-muted-foreground'>
|
||||
屏蔽
|
||||
</p>
|
||||
<FieldDescription>
|
||||
命中返回 false,优先级高于匹配
|
||||
</FieldDescription>
|
||||
</div>
|
||||
<Field
|
||||
orientation='horizontal'
|
||||
className='items-start justify-between gap-3'
|
||||
>
|
||||
<div className='space-y-1'>
|
||||
<FieldLabel htmlFor={`${node.id}-block-bots`}>
|
||||
屏蔽常见爬虫 UA
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
浏览器或操作系统分类为 Bot(含 bot / spider / crawler /
|
||||
slurp 等特征,如 Googlebot)
|
||||
</FieldDescription>
|
||||
</div>
|
||||
<Switch
|
||||
id={`${node.id}-block-bots`}
|
||||
className='mt-0.5'
|
||||
checked={node.config.block_common_bots}
|
||||
onCheckedChange={(block_common_bots) =>
|
||||
onChange({
|
||||
...node,
|
||||
config: { ...node.config, block_common_bots },
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
orientation='horizontal'
|
||||
className='items-start justify-between gap-3'
|
||||
>
|
||||
<div className='space-y-1'>
|
||||
<FieldLabel htmlFor={`${node.id}-block-abnormal`}>
|
||||
屏蔽非正常 UA
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
浏览器分类为 Bot、Other 或 Unknown(无法识别为已知浏览器)
|
||||
</FieldDescription>
|
||||
</div>
|
||||
<Switch
|
||||
id={`${node.id}-block-abnormal`}
|
||||
className='mt-0.5'
|
||||
checked={node.config.block_abnormal_ua}
|
||||
onCheckedChange={(block_abnormal_ua) =>
|
||||
onChange({
|
||||
...node,
|
||||
config: { ...node.config, block_abnormal_ua },
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</FieldGroup>
|
||||
);
|
||||
if (node.type === 'pow')
|
||||
|
||||
Reference in New Issue
Block a user