if server says it's valid, it's valid

This commit is contained in:
EthanHealy01 2025-10-15 15:35:43 +01:00
parent d0e629aa1f
commit ea3f3a1440
5 changed files with 25 additions and 59 deletions

View File

@ -25,13 +25,8 @@ const useFileSummary = (results: SignatureValidationReportEntry[]) => {
results.forEach((result) => {
signatureCount += result.signatures.length;
result.signatures.forEach((signature) => {
const isFullyValid =
signature.valid &&
signature.chainValid &&
signature.trustValid &&
signature.notExpired &&
signature.notRevoked;
if (isFullyValid) {
const isValid = signature.valid;
if (isValid) {
fullyValidCount += 1;
}
});
@ -157,7 +152,7 @@ const ValidateSignatureResults = ({
: hasSignatures
? allValid
? t('validateSignature.status.valid', 'Valid')
: t('validateSignature.status.needsAttention', 'Needs Attention')
: t('validateSignature.status.invalid', 'Invalid')
: t('validateSignature.noSignaturesShort', 'No signatures');
const badgeClass = hasError
? 'status-badge status-badge--invalid'

View File

@ -20,9 +20,8 @@ export const deriveEntryStatus = (
};
}
const allValid = entry.signatures.every(
(sig) => sig.valid && sig.chainValid && sig.trustValid && sig.notExpired && sig.notRevoked
);
// File-level status is Valid only if every signature is cryptographically valid.
const allValid = entry.signatures.every((sig) => sig.valid);
if (allValid) {
return {
@ -32,7 +31,7 @@ export const deriveEntryStatus = (
}
return {
text: t('validateSignature.status.reviewMissingFields', 'Needs Attention: Missing Fields'),
color: colorPalette.warning,
text: t('validateSignature.status.invalid', 'Invalid'),
color: colorPalette.danger,
};
};

View File

@ -9,7 +9,8 @@ const buildCsvRows = (entries: SignatureValidationReportEntry[]): string[][] =>
'chainValid',
'trustValid',
'notExpired',
'notRevoked',
'revocationChecked',
'revocationStatus',
'signerName',
'signatureDate',
'reason',
@ -39,7 +40,8 @@ const buildCsvRows = (entries: SignatureValidationReportEntry[]): string[][] =>
booleanToString(signature.chainValid),
booleanToString(signature.trustValid),
booleanToString(signature.notExpired),
booleanToString(signature.notRevoked),
booleanToString(signature.revocationChecked),
signature.revocationStatus || '',
signature.signerName || '',
signature.signatureDate || '',
signature.reason || '',
@ -80,6 +82,7 @@ const buildCsvRows = (entries: SignatureValidationReportEntry[]): string[][] =>
'',
'',
'',
'',
fileResult.error || ''
]);
}

View File

@ -39,36 +39,18 @@ export const computeSignatureStatus = (
trustIssues.push(t('validateSignature.issue.certExpired', 'Certificate expired'));
}
// Use new revocationStatus field if available, fallback to notRevoked for backward compatibility
const revStatus = signature.revocationStatus || (signature.notRevoked ? 'good' : 'unknown');
// Use revocationStatus from backend; default to 'unknown' when absent
const revStatus = signature.revocationStatus ?? 'unknown';
if (revStatus === 'revoked') {
trustIssues.push(t('validateSignature.issue.certRevoked', 'Certificate revoked'));
} else if (revStatus === 'soft-fail') {
trustIssues.push(t('validateSignature.issue.certRevocationUnknown', 'Certificate revocation status unknown'));
}
// Don't report anything for 'not-checked', 'good', or 'unknown' unless actually revoked
// Check for missing common metadata fields
const missing: string[] = [];
if (!signature.signerName || signature.signerName.trim().length === 0) missing.push(t('validateSignature.signer', 'Signer'));
if (!signature.reason || signature.reason.trim().length === 0) missing.push(t('validateSignature.reason', 'Reason'));
if (!signature.location || signature.location.trim().length === 0) missing.push(t('validateSignature.location', 'Location'));
// Aggregate all issues for details UI
// Aggregate all issues for details UI (ignore missing metadata fields; they are optional)
issues.push(...trustIssues);
if (missing.length > 0) {
issues.push(t('validateSignature.issue.missingFields', 'Missing fields') + `: ${missing.join(', ')}`);
}
if (issues.length === 0) {
return {
kind: 'valid',
label: t('validateSignature.status.validFull', 'Fully Valid'),
details: [],
};
}
// Invalid ONLY when cryptographic signature itself failed or an explicit backend error occurred
// If cryptographic validation failed, mark as Invalid
if (!signature.valid) {
return {
kind: 'invalid',
@ -77,29 +59,10 @@ export const computeSignatureStatus = (
};
}
// Otherwise, it's a signed document with issues
const onlyMissing = missing.length > 0 && trustIssues.length === 0;
const onlyTrust = missing.length === 0 && trustIssues.length > 0;
if (onlyMissing) {
return {
kind: 'warning',
label: t('validateSignature.status.missingFields', 'Needs Attention: Missing Fields'),
details: issues,
};
}
if (onlyTrust) {
return {
kind: 'warning',
label: t('validateSignature.status.trustIssues', 'Needs Attention: Trust/Chain'),
details: issues,
};
}
// Otherwise, mark as Valid regardless of optional field presence and trust warnings
return {
kind: 'warning',
label: t('validateSignature.status.needsAttention', 'Needs Attention'),
kind: 'valid',
label: t('validateSignature.status.valid', 'Valid'),
details: issues,
};
};

View File

@ -59,6 +59,12 @@ export const normalizeBackendResult = (
chainValid: Boolean(item.chainValid),
trustValid: Boolean(item.trustValid),
notExpired: Boolean(item.notExpired),
revocationChecked:
item.revocationChecked === null || item.revocationChecked === undefined
? null
: Boolean(item.revocationChecked),
revocationStatus: item.revocationStatus ? coerceString(item.revocationStatus) : null,
validationTimeSource: item.validationTimeSource ? coerceString(item.validationTimeSource) : null,
signerName: coerceString(item.signerName),
signatureDate: coerceString(item.signatureDate),
reason: coerceString(item.reason),