mirror of
https://github.com/yaklang/yaklang-chrome-extension.git
synced 2026-09-24 20:21:53 +08:00
78 lines
2.8 KiB
TypeScript
78 lines
2.8 KiB
TypeScript
import type {
|
|
BrowserAuthorizationBaseline,
|
|
BrowserTransformProfile,
|
|
} from '@/types/models';
|
|
import { ExtensionError } from '@/shared/errors';
|
|
|
|
const DYNAMIC_FIELD_CATEGORIES = new Set(['signature', 'nonce', 'timestamp', 'csrf']);
|
|
|
|
function normalizedTransformDestination(destination: string): string {
|
|
const trimmed = destination.trim();
|
|
if (trimmed.toLowerCase().startsWith('header.')) {
|
|
return `header.${trimmed.slice(7).trim().toLowerCase()}`;
|
|
}
|
|
return trimmed;
|
|
}
|
|
|
|
export function authorizationDynamicTransformDestinations(
|
|
baseline: BrowserAuthorizationBaseline,
|
|
profile: BrowserTransformProfile,
|
|
): string[] {
|
|
if (!profile.enabled || !profile.request.enabled) {
|
|
throw new ExtensionError('authorization_transform_unavailable', '所选明文网关未启用请求转换');
|
|
}
|
|
if (profile.recovery && profile.recovery.state !== 'ready') {
|
|
throw new ExtensionError('authorization_transform_stale', '所选明文网关正在等待文档恢复或重新验证');
|
|
}
|
|
const dynamicFields = new Map(
|
|
baseline.request.fields
|
|
.filter((field) => DYNAMIC_FIELD_CATEGORIES.has(field.category))
|
|
.map((field) => [
|
|
normalizedTransformDestination(field.path),
|
|
field,
|
|
]),
|
|
);
|
|
const required = [...dynamicFields.keys()].filter((path) => {
|
|
const field = dynamicFields.get(path);
|
|
return field?.category === 'signature'
|
|
|| field?.category === 'nonce'
|
|
|| field?.category === 'timestamp';
|
|
});
|
|
if (!required.length) {
|
|
throw new ExtensionError('authorization_transform_unnecessary', '当前授权基线没有需要动态重算的签名、Nonce 或时间字段');
|
|
}
|
|
const destinations = profile.request.nodes
|
|
.filter((node) => node.kind === 'output.write')
|
|
.map((node) => normalizedTransformDestination(node.destination));
|
|
if (!destinations.length) {
|
|
throw new ExtensionError('authorization_transform_invalid', '所选明文网关没有请求输出节点');
|
|
}
|
|
for (const destination of destinations) {
|
|
if (
|
|
destination === 'body'
|
|
|| destination.startsWith('body.')
|
|
|| (!destination.startsWith('header.') && !destination.startsWith('query.'))
|
|
) {
|
|
throw new ExtensionError(
|
|
'authorization_transform_unsupported',
|
|
'首批授权动态重算只接受 Header/Query 签名字段;Body 加密 envelope 需要逻辑明文绑定',
|
|
);
|
|
}
|
|
if (!dynamicFields.has(destination)) {
|
|
throw new ExtensionError(
|
|
'authorization_transform_invalid',
|
|
`明文网关输出未对应基线中的动态字段: ${destination}`,
|
|
);
|
|
}
|
|
}
|
|
const output = [...new Set(destinations)];
|
|
const missing = required.find((path) => !output.includes(path));
|
|
if (missing) {
|
|
throw new ExtensionError(
|
|
'authorization_transform_incomplete',
|
|
`明文网关尚未覆盖动态字段: ${missing}`,
|
|
);
|
|
}
|
|
return output.sort();
|
|
}
|