mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-23 22:20:13 +08:00
🐛 fix(security): 完善密文升级导入覆盖与安全更新链路
- 完善连接恢复包与 legacy 导入覆盖语义及密文兼容处理 - 修复安全更新详情高亮反馈与相关前后端链路 - 补强 keyring 误判边界与安全更新回归测试
This commit is contained in:
@@ -54,6 +54,10 @@ type StartSecurityUpdateResult = {
|
||||
error: Error | null;
|
||||
};
|
||||
|
||||
type MergeSecurityUpdateStatusOptions = {
|
||||
previousStatus?: Partial<SecurityUpdateStatus> | null;
|
||||
};
|
||||
|
||||
const defaultSummary = () => ({
|
||||
total: 0,
|
||||
updated: 0,
|
||||
@@ -129,9 +133,56 @@ const mergeSecurityUpdateIssues = (
|
||||
};
|
||||
};
|
||||
|
||||
const isLocalLegacyIssue = (issue: Partial<SecurityUpdateIssue> | null | undefined): boolean => {
|
||||
const issueId = String(issue?.id || '').trim();
|
||||
return issueId.startsWith('legacy-connection-') || issueId === 'legacy-global-proxy-default';
|
||||
};
|
||||
|
||||
const countLocalLegacyIssues = (issues: SecurityUpdateIssue[]): number => (
|
||||
issues.filter((issue) => isLocalLegacyIssue(issue)).length
|
||||
);
|
||||
|
||||
const deriveLegacySummary = (
|
||||
base: SecurityUpdateStatus,
|
||||
currentLegacyCount: number,
|
||||
previousStatus?: Partial<SecurityUpdateStatus> | null,
|
||||
): {
|
||||
summary: SecurityUpdateSummary;
|
||||
hasContribution: boolean;
|
||||
} => {
|
||||
const previousSummary = previousStatus?.summary ?? defaultSummary();
|
||||
const previousIssues = Array.isArray(previousStatus?.issues) ? previousStatus.issues : [];
|
||||
const previousLegacyCount = countLocalLegacyIssues(previousIssues);
|
||||
const previousLegacyTotal = Math.max(
|
||||
0,
|
||||
previousSummary.total - base.summary.total,
|
||||
previousSummary.updated - base.summary.updated + previousLegacyCount,
|
||||
previousLegacyCount,
|
||||
);
|
||||
const previousLegacyUpdated = Math.max(
|
||||
0,
|
||||
Math.min(previousLegacyTotal, previousSummary.updated - base.summary.updated),
|
||||
);
|
||||
const repairedSincePrevious = Math.max(0, previousLegacyCount - currentLegacyCount);
|
||||
const nextLegacyUpdated = Math.min(previousLegacyTotal, previousLegacyUpdated + repairedSincePrevious);
|
||||
const nextLegacyTotal = Math.max(previousLegacyTotal, nextLegacyUpdated + currentLegacyCount);
|
||||
|
||||
return {
|
||||
summary: {
|
||||
total: base.summary.total + nextLegacyTotal,
|
||||
updated: base.summary.updated + nextLegacyUpdated,
|
||||
pending: base.summary.pending + currentLegacyCount,
|
||||
skipped: base.summary.skipped,
|
||||
failed: base.summary.failed,
|
||||
},
|
||||
hasContribution: nextLegacyTotal > 0,
|
||||
};
|
||||
};
|
||||
|
||||
export const mergeSecurityUpdateStatusWithLegacySource = (
|
||||
status: Partial<SecurityUpdateStatus> | undefined,
|
||||
rawPayload: string | null,
|
||||
options?: MergeSecurityUpdateStatusOptions,
|
||||
): SecurityUpdateStatus => {
|
||||
const base: SecurityUpdateStatus = {
|
||||
...defaultStatus(),
|
||||
@@ -142,46 +193,51 @@ export const mergeSecurityUpdateStatusWithLegacySource = (
|
||||
},
|
||||
issues: Array.isArray(status?.issues) ? status.issues : [],
|
||||
};
|
||||
const baseNonLegacyIssues = base.issues.filter((issue) => !isLocalLegacyIssue(issue));
|
||||
|
||||
const legacy = buildLegacyPendingDetails(rawPayload);
|
||||
if (!legacy.hasLegacyItems) {
|
||||
const legacySummary = deriveLegacySummary(base, legacy.issues.length, options?.previousStatus);
|
||||
|
||||
if (!legacySummary.hasContribution) {
|
||||
return base;
|
||||
}
|
||||
|
||||
const mergedIssues = mergeSecurityUpdateIssues(baseNonLegacyIssues, legacy.issues).issues;
|
||||
|
||||
if (base.overallStatus === 'not_detected') {
|
||||
if (!legacy.hasLegacyItems) {
|
||||
return base;
|
||||
}
|
||||
return {
|
||||
...base,
|
||||
overallStatus: 'pending',
|
||||
reminderVisible: true,
|
||||
canStart: true,
|
||||
canPostpone: true,
|
||||
summary: legacy.summary,
|
||||
issues: legacy.issues,
|
||||
summary: legacySummary.summary,
|
||||
issues: mergedIssues,
|
||||
};
|
||||
}
|
||||
|
||||
if (base.overallStatus === 'pending' || base.overallStatus === 'postponed') {
|
||||
const mergedIssues = mergeSecurityUpdateIssues(base.issues, legacy.issues);
|
||||
const summary = hasMeaningfulSummary(base.summary)
|
||||
? {
|
||||
total: base.summary.total + mergedIssues.addedCount,
|
||||
updated: base.summary.updated,
|
||||
pending: base.summary.pending + mergedIssues.addedCount,
|
||||
skipped: base.summary.skipped,
|
||||
failed: base.summary.failed,
|
||||
}
|
||||
: legacy.summary;
|
||||
|
||||
return {
|
||||
...base,
|
||||
summary,
|
||||
issues: mergedIssues.issues,
|
||||
summary: hasMeaningfulSummary(base.summary) || legacy.hasLegacyItems ? legacySummary.summary : legacy.summary,
|
||||
issues: mergedIssues,
|
||||
canStart: true,
|
||||
canPostpone: true,
|
||||
reminderVisible: base.overallStatus === 'pending' ? true : base.reminderVisible,
|
||||
};
|
||||
}
|
||||
|
||||
if (base.overallStatus === 'rolled_back' || base.overallStatus === 'needs_attention') {
|
||||
return {
|
||||
...base,
|
||||
summary: hasMeaningfulSummary(base.summary) || legacy.hasLegacyItems ? legacySummary.summary : legacy.summary,
|
||||
issues: mergedIssues,
|
||||
};
|
||||
}
|
||||
|
||||
return base;
|
||||
};
|
||||
|
||||
@@ -344,6 +400,7 @@ export async function startSecurityUpdateFromBootstrap(args: SecureConfigBootstr
|
||||
|
||||
export type {
|
||||
BackendGlobalProxyResult,
|
||||
MergeSecurityUpdateStatusOptions,
|
||||
SecurityUpdateBackend,
|
||||
SecureConfigBootstrapArgs,
|
||||
SecureConfigBootstrapResult,
|
||||
|
||||
Reference in New Issue
Block a user