File size: 3,553 Bytes
daa8246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
const NON_REDIRECTABLE_STATUS_CODES = new Set([504, 524]);

export const STATUS_CODE_RISK_I18N_KEYS = {
  title: '高危操作确认',
  detailTitle: '检测到以下高危状态码重定向规则',
  inputPrompt: '操作确认',
  confirmButton: '我确认开启高危重试',
  markdown: '高危状态码重试风险告知与免责声明Markdown',
  confirmText: '高危状态码重试风险确认输入文本',
  inputPlaceholder: '高危状态码重试风险输入框占位文案',
  mismatchText: '高危状态码重试风险输入不匹配提示',
};

export const STATUS_CODE_RISK_CHECKLIST_KEYS = [
  '高危状态码重试风险确认项1',
  '高危状态码重试风险确认项2',
  '高危状态码重试风险确认项3',
  '高危状态码重试风险确认项4',
];

function parseStatusCodeKey(rawKey) {
  if (typeof rawKey !== 'string') {
    return null;
  }
  const normalized = rawKey.trim();
  if (!/^[1-5]\d{2}$/.test(normalized)) {
    return null;
  }
  return Number.parseInt(normalized, 10);
}

function parseStatusCodeMappingTarget(rawValue) {
  if (typeof rawValue === 'number' && Number.isInteger(rawValue)) {
    return rawValue >= 100 && rawValue <= 599 ? rawValue : null;
  }
  if (typeof rawValue === 'string') {
    const normalized = rawValue.trim();
    if (!/^[1-5]\d{2}$/.test(normalized)) {
      return null;
    }
    const code = Number.parseInt(normalized, 10);
    return code >= 100 && code <= 599 ? code : null;
  }
  return null;
}

export function collectInvalidStatusCodeEntries(statusCodeMappingStr) {
  if (
    typeof statusCodeMappingStr !== 'string' ||
    statusCodeMappingStr.trim() === ''
  ) {
    return [];
  }

  let parsed;
  try {
    parsed = JSON.parse(statusCodeMappingStr);
  } catch {
    return [];
  }

  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
    return [];
  }

  const invalid = [];
  for (const [rawKey, rawValue] of Object.entries(parsed)) {
    const fromCode = parseStatusCodeKey(rawKey);
    const toCode = parseStatusCodeMappingTarget(rawValue);
    if (fromCode === null || toCode === null) {
      invalid.push(`${rawKey}${rawValue}`);
    }
  }

  return invalid;
}

export function collectDisallowedStatusCodeRedirects(statusCodeMappingStr) {
  if (
    typeof statusCodeMappingStr !== 'string' ||
    statusCodeMappingStr.trim() === ''
  ) {
    return [];
  }

  let parsed;
  try {
    parsed = JSON.parse(statusCodeMappingStr);
  } catch (error) {
    return [];
  }

  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
    return [];
  }

  const riskyMappings = [];
  Object.entries(parsed).forEach(([rawFrom, rawTo]) => {
    const fromCode = parseStatusCodeKey(rawFrom);
    const toCode = parseStatusCodeMappingTarget(rawTo);
    if (fromCode === null || toCode === null) {
      return;
    }
    if (!NON_REDIRECTABLE_STATUS_CODES.has(fromCode)) {
      return;
    }
    if (fromCode === toCode) {
      return;
    }
    riskyMappings.push(`${fromCode} -> ${toCode}`);
  });

  return Array.from(new Set(riskyMappings)).sort();
}

export function collectNewDisallowedStatusCodeRedirects(
  originalStatusCodeMappingStr,
  currentStatusCodeMappingStr,
) {
  const currentRisky = collectDisallowedStatusCodeRedirects(
    currentStatusCodeMappingStr,
  );
  if (currentRisky.length === 0) {
    return [];
  }

  const originalRiskySet = new Set(
    collectDisallowedStatusCodeRedirects(originalStatusCodeMappingStr),
  );

  return currentRisky.filter((mapping) => !originalRiskySet.has(mapping));
}