删除规则组的引用拦截连附加规则一起查
之前只扫顶层 rules。附加规则(sub-rules)里的 RULE-SET 引用漏过的话, 删除会被内核重载拒掉——保护链路能回滚,但用户看到的是解析错误原文 而不是「谁在引用它」。
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
|||||||
ruleSetReferences,
|
ruleSetReferences,
|
||||||
setRuleProviders,
|
setRuleProviders,
|
||||||
setRules,
|
setRules,
|
||||||
|
subRuleSetReferences,
|
||||||
} from './rules.ts'
|
} from './rules.ts'
|
||||||
import type { ConfigObject } from '../vendor/config-editor/index.ts'
|
import type { ConfigObject } from '../vendor/config-editor/index.ts'
|
||||||
|
|
||||||
@@ -316,3 +317,17 @@ describe('清单格式与缓存路径', () => {
|
|||||||
expect(ruleProviderPathConflict(data, 'x', ruleProviderPath('x', 'yaml'))).toBeNull()
|
expect(ruleProviderPathConflict(data, 'x', ruleProviderPath('x', 'yaml'))).toBeNull()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('附加规则里的规则组引用', () => {
|
||||||
|
it('sub-rules 各表里的 RULE-SET 引用都认出来,别的表不误报', () => {
|
||||||
|
const data = {
|
||||||
|
'sub-rules': {
|
||||||
|
'patchbay:t1 附加': ['RULE-SET,ads,REJECT', 'MATCH,patchbay:t1'],
|
||||||
|
mine: ['RULE-SET,other,DIRECT'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expect(subRuleSetReferences(data, 'ads')).toEqual(['RULE-SET,ads,REJECT'])
|
||||||
|
expect(subRuleSetReferences(data, 'ghost')).toEqual([])
|
||||||
|
expect(subRuleSetReferences({}, 'ads')).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -168,6 +168,28 @@ export function ruleSetReferences(rules: string[], providerName: string): number
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sub-rules 各表(含每路入站的附加规则)里引用这个规则组的规则原文。
|
||||||
|
* 删除规则组前和顶层的一起查——漏了的话删除会被内核重载拒掉,用户看到的
|
||||||
|
* 是一段原始解析错误而不是「谁在引用它」。
|
||||||
|
*/
|
||||||
|
export function subRuleSetReferences(data: ConfigObject, providerName: string): string[] {
|
||||||
|
const tables = data['sub-rules']
|
||||||
|
if (typeof tables !== 'object' || tables === null || Array.isArray(tables)) return []
|
||||||
|
const hits: string[] = []
|
||||||
|
for (const rules of Object.values(tables)) {
|
||||||
|
if (!Array.isArray(rules)) continue
|
||||||
|
for (const rule of rules) {
|
||||||
|
if (typeof rule !== 'string') continue
|
||||||
|
const parsed = parseRule(rule)
|
||||||
|
if (parsed.type.toUpperCase() === 'RULE-SET' && parsed.payload === providerName) {
|
||||||
|
hits.push(rule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hits
|
||||||
|
}
|
||||||
|
|
||||||
/** 配置里的 rule-providers 段。不是映射就当没有。 */
|
/** 配置里的 rule-providers 段。不是映射就当没有。 */
|
||||||
export function ruleProvidersOf(data: ConfigObject): Record<string, ConfigObject> {
|
export function ruleProvidersOf(data: ConfigObject): Record<string, ConfigObject> {
|
||||||
const value = data['rule-providers']
|
const value = data['rule-providers']
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
rulesOf,
|
rulesOf,
|
||||||
setRuleProviders,
|
setRuleProviders,
|
||||||
setRules,
|
setRules,
|
||||||
|
subRuleSetReferences,
|
||||||
} from '@shared/rules.ts'
|
} from '@shared/rules.ts'
|
||||||
import type { IniImportPlan, RuleIssue } from '@shared/rules.ts'
|
import type { IniImportPlan, RuleIssue } from '@shared/rules.ts'
|
||||||
import type { ConfigObject } from '../../vendor/config-editor/index.ts'
|
import type { ConfigObject } from '../../vendor/config-editor/index.ts'
|
||||||
@@ -290,9 +291,14 @@ function onBlockedBackdrop(event: MouseEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function askRemoveProvider(name: string) {
|
function askRemoveProvider(name: string) {
|
||||||
const refs = ruleSetReferences(rules.value, name)
|
// 附加规则(sub-rules)里的引用也要查:漏了的话删除会被内核重载拒掉,
|
||||||
|
// 用户看到的是解析错误原文而不是「谁在引用它」
|
||||||
|
const refs = [
|
||||||
|
...ruleSetReferences(rules.value, name).map((i) => rules.value[i]!),
|
||||||
|
...subRuleSetReferences(props.data, name),
|
||||||
|
]
|
||||||
if (refs.length > 0) {
|
if (refs.length > 0) {
|
||||||
blockedProvider.value = { name, refs: refs.map((i) => rules.value[i]!) }
|
blockedProvider.value = { name, refs }
|
||||||
} else {
|
} else {
|
||||||
removingProvider.value = name
|
removingProvider.value = name
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user