@redsift/products 12.5.7 → 12.5.8-muiv8-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -404,6 +404,37 @@ var EXTRACTOR_STRINGS = {
|
|
|
404
404
|
"card.bimi.vmc.issuer_md": "**Issuer: {issuer}**",
|
|
405
405
|
"card.bimi.vmc.trademarkAuthority_md": "**Trademark Authority: {trademarkAuthority}**",
|
|
406
406
|
"card.bimi.vmc.valid-for-domain_md": "**Valid for domains:** `{domains}`",
|
|
407
|
+
// BIMI VMC/CMC published-certificate metadata (WEB-1137 / DS-93)
|
|
408
|
+
// Validity
|
|
409
|
+
"card.bimi.vmc.cert-section-validity": "Validity",
|
|
410
|
+
"card.bimi.vmc.cert-valid-from_md": "**Start:** {date}",
|
|
411
|
+
"card.bimi.vmc.cert-expiry_md": "**Expiry:** {date}",
|
|
412
|
+
// Certificate
|
|
413
|
+
"card.bimi.vmc.cert-section-certificate": "Certificate",
|
|
414
|
+
"card.bimi.vmc.cert-issuer-common-name_md": "**Issuer:** {issuerCommonName}",
|
|
415
|
+
"card.bimi.vmc.cert-issuer-organization_md": "**Issuer organization:** {issuerOrganization}",
|
|
416
|
+
"card.bimi.vmc.cert-issuer-country_md": "**Issuer country:** {issuerCountry}",
|
|
417
|
+
"card.bimi.vmc.cert-type_md": "**Certificate type:** {assertionMarkType}",
|
|
418
|
+
"card.bimi.vmc.cert-certified-domains_md": "**Certified domains:** `{certifiedDomains}`",
|
|
419
|
+
// Subject identity
|
|
420
|
+
"card.bimi.vmc.cert-section-subject-identity": "Subject identity",
|
|
421
|
+
"card.bimi.vmc.cert-serial-number_md": "**Serial number:** {serialNumber}",
|
|
422
|
+
"card.bimi.vmc.cert-organization_md": "**Organization:** {organization}",
|
|
423
|
+
"card.bimi.vmc.cert-common-name_md": "**Common name:** {commonName}",
|
|
424
|
+
"card.bimi.vmc.cert-business-category_md": "**Business category:** {businessCategory}",
|
|
425
|
+
"card.bimi.vmc.cert-organization-identifier_md": "**Organization identifier:** {organizationIdentifier}",
|
|
426
|
+
"card.bimi.vmc.cert-legal-entity-identifier_md": "**Legal entity identifier:** {legalEntityIdentifier}",
|
|
427
|
+
"card.bimi.vmc.cert-jurisdiction_md": "**Jurisdiction:** {jurisdiction}",
|
|
428
|
+
"card.bimi.vmc.cert-address_md": "**Address:** {address}",
|
|
429
|
+
// Mark evidence
|
|
430
|
+
"card.bimi.vmc.cert-section-mark-evidence": "Mark evidence",
|
|
431
|
+
"card.bimi.vmc.cert-trademark-registration_md": "**Trademark registration:** {trademarkRegistration}",
|
|
432
|
+
"card.bimi.vmc.cert-trademark-office_md": "**Trademark office:** {trademarkOfficeName}",
|
|
433
|
+
"card.bimi.vmc.cert-mark-type_md": "**Mark type:** {markType}",
|
|
434
|
+
"card.bimi.vmc.cert-trademark-country_md": "**Trademark country or region:** {trademarkCountryOrRegion}",
|
|
435
|
+
// Verification issues
|
|
436
|
+
"card.bimi.vmc.cert-section-verification-issues": "Verification issues",
|
|
437
|
+
"card.bimi.vmc.cert-no-issues-reported_md": "None reported",
|
|
407
438
|
// BIMI section titles
|
|
408
439
|
"section-titles.bimi-domain": "DMARC Domains",
|
|
409
440
|
"section-titles.bimi-policy": "Your BIMI Policy",
|
|
@@ -843,6 +874,37 @@ var EXTRACTOR_STRINGS = {
|
|
|
843
874
|
"card.bimi.vmc.issuer_md": "**Issuer : {issuer}**",
|
|
844
875
|
"card.bimi.vmc.trademarkAuthority_md": "**Autorit\xE9 de la marque : {trademarkAuthority}**",
|
|
845
876
|
"card.bimi.vmc.valid-for-domain_md": "**Valide pour les domaines :** `{domains}`",
|
|
877
|
+
// BIMI VMC/CMC published-certificate metadata (WEB-1137 / DS-93)
|
|
878
|
+
// Validity
|
|
879
|
+
"card.bimi.vmc.cert-section-validity": "Validit\xE9",
|
|
880
|
+
"card.bimi.vmc.cert-valid-from_md": "**D\xE9but :** {date}",
|
|
881
|
+
"card.bimi.vmc.cert-expiry_md": "**Expiration :** {date}",
|
|
882
|
+
// Certificate
|
|
883
|
+
"card.bimi.vmc.cert-section-certificate": "Certificat",
|
|
884
|
+
"card.bimi.vmc.cert-issuer-common-name_md": "**\xC9metteur :** {issuerCommonName}",
|
|
885
|
+
"card.bimi.vmc.cert-issuer-organization_md": "**Organisation de l'\xE9metteur :** {issuerOrganization}",
|
|
886
|
+
"card.bimi.vmc.cert-issuer-country_md": "**Pays de l'\xE9metteur :** {issuerCountry}",
|
|
887
|
+
"card.bimi.vmc.cert-type_md": "**Type de certificat :** {assertionMarkType}",
|
|
888
|
+
"card.bimi.vmc.cert-certified-domains_md": "**Domaines certifi\xE9s :** `{certifiedDomains}`",
|
|
889
|
+
// Subject identity
|
|
890
|
+
"card.bimi.vmc.cert-section-subject-identity": "Identit\xE9 du sujet",
|
|
891
|
+
"card.bimi.vmc.cert-serial-number_md": "**Num\xE9ro de s\xE9rie :** {serialNumber}",
|
|
892
|
+
"card.bimi.vmc.cert-organization_md": "**Organisation :** {organization}",
|
|
893
|
+
"card.bimi.vmc.cert-common-name_md": "**Nom commun :** {commonName}",
|
|
894
|
+
"card.bimi.vmc.cert-business-category_md": "**Cat\xE9gorie d'activit\xE9 :** {businessCategory}",
|
|
895
|
+
"card.bimi.vmc.cert-organization-identifier_md": "**Identifiant de l'organisation :** {organizationIdentifier}",
|
|
896
|
+
"card.bimi.vmc.cert-legal-entity-identifier_md": "**Identifiant d'entit\xE9 juridique :** {legalEntityIdentifier}",
|
|
897
|
+
"card.bimi.vmc.cert-jurisdiction_md": "**Juridiction :** {jurisdiction}",
|
|
898
|
+
"card.bimi.vmc.cert-address_md": "**Adresse :** {address}",
|
|
899
|
+
// Mark evidence
|
|
900
|
+
"card.bimi.vmc.cert-section-mark-evidence": "Preuve de la marque",
|
|
901
|
+
"card.bimi.vmc.cert-trademark-registration_md": "**Enregistrement de la marque :** {trademarkRegistration}",
|
|
902
|
+
"card.bimi.vmc.cert-trademark-office_md": "**Office des marques :** {trademarkOfficeName}",
|
|
903
|
+
"card.bimi.vmc.cert-mark-type_md": "**Type de marque :** {markType}",
|
|
904
|
+
"card.bimi.vmc.cert-trademark-country_md": "**Pays ou r\xE9gion de la marque :** {trademarkCountryOrRegion}",
|
|
905
|
+
// Verification issues
|
|
906
|
+
"card.bimi.vmc.cert-section-verification-issues": "Probl\xE8mes de v\xE9rification",
|
|
907
|
+
"card.bimi.vmc.cert-no-issues-reported_md": "Aucun signal\xE9",
|
|
846
908
|
// BIMI section titles
|
|
847
909
|
"section-titles.bimi-domain": "Domaines DMARC",
|
|
848
910
|
"section-titles.bimi-policy": "Votre politique BIMI",
|
|
@@ -7957,6 +8019,277 @@ const uncompressLogo = svgUrl => {
|
|
|
7957
8019
|
|
|
7958
8020
|
var SVGLogo$1 = SVGLogo;
|
|
7959
8021
|
|
|
8022
|
+
/**
|
|
8023
|
+
* A rendered published-certificate section: a titled group of Checklist items.
|
|
8024
|
+
*/
|
|
8025
|
+
|
|
8026
|
+
/**
|
|
8027
|
+
* Reference URL for the BIMI certificate-type explainer, used by the VMC/CMC
|
|
8028
|
+
* type badge. Follows the existing external-link convention in the card.
|
|
8029
|
+
*/
|
|
8030
|
+
const CERT_TYPE_REFERENCE_URL = 'https://bimigroup.org/verified-mark-certificates-vmc-and-bimi/';
|
|
8031
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
8032
|
+
|
|
8033
|
+
/**
|
|
8034
|
+
* Parse a YYYY-MM-DD date string to a UTC Date. Returns null when the input is
|
|
8035
|
+
* missing or unparseable so callers can degrade gracefully.
|
|
8036
|
+
*/
|
|
8037
|
+
const parseIsoDate = value => {
|
|
8038
|
+
if (!value) return null;
|
|
8039
|
+
const parsed = new Date(`${value}T00:00:00Z`);
|
|
8040
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
8041
|
+
};
|
|
8042
|
+
|
|
8043
|
+
/** Whole-day difference between two dates (b - a), truncated toward zero. */
|
|
8044
|
+
const diffInDays = (a, b) => Math.trunc((b.getTime() - a.getTime()) / DAY_MS);
|
|
8045
|
+
|
|
8046
|
+
/**
|
|
8047
|
+
* Humanize the certificate validity start: "Active for {n} days — Since {date}".
|
|
8048
|
+
* The humanized duration is a render-layer responsibility (the API returns only
|
|
8049
|
+
* the raw validFrom date). Falls back to just the date when duration can't be
|
|
8050
|
+
* computed.
|
|
8051
|
+
*/
|
|
8052
|
+
const humanizeValidFrom = (validFrom, now) => {
|
|
8053
|
+
const from = parseIsoDate(validFrom);
|
|
8054
|
+
if (!from) return undefined;
|
|
8055
|
+
const days = diffInDays(from, now);
|
|
8056
|
+
if (days < 0) {
|
|
8057
|
+
// validFrom is in the future — not yet active; show the raw date only.
|
|
8058
|
+
return `Not yet active — Since ${validFrom}`;
|
|
8059
|
+
}
|
|
8060
|
+
const unit = days === 1 ? 'day' : 'days';
|
|
8061
|
+
return `Active for ${days} ${unit} — Since ${validFrom}`;
|
|
8062
|
+
};
|
|
8063
|
+
|
|
8064
|
+
/**
|
|
8065
|
+
* Humanize the certificate expiry: "Expires in {n} days — On {date}", or
|
|
8066
|
+
* "Expired {n} days ago — On {date}" when already past. Falls back to the raw
|
|
8067
|
+
* date when duration can't be computed.
|
|
8068
|
+
*/
|
|
8069
|
+
const humanizeExpiry = (expiry, now) => {
|
|
8070
|
+
const to = parseIsoDate(expiry);
|
|
8071
|
+
if (!to) return undefined;
|
|
8072
|
+
const days = diffInDays(now, to);
|
|
8073
|
+
if (days < 0) {
|
|
8074
|
+
const ago = Math.abs(days);
|
|
8075
|
+
const unit = ago === 1 ? 'day' : 'days';
|
|
8076
|
+
return `Expired ${ago} ${unit} ago — On ${expiry}`;
|
|
8077
|
+
}
|
|
8078
|
+
const unit = days === 1 ? 'day' : 'days';
|
|
8079
|
+
return `Expires in ${days} ${unit} — On ${expiry}`;
|
|
8080
|
+
};
|
|
8081
|
+
|
|
8082
|
+
/** Join defined, non-empty parts with a separator; undefined when nothing remains. */
|
|
8083
|
+
const joinParts = function (parts) {
|
|
8084
|
+
let sep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ', ';
|
|
8085
|
+
const filtered = parts.map(p => p === null || p === void 0 ? void 0 : p.trim()).filter(p => !!p);
|
|
8086
|
+
return filtered.length ? filtered.join(sep) : undefined;
|
|
8087
|
+
};
|
|
8088
|
+
|
|
8089
|
+
/**
|
|
8090
|
+
* Build a single info ChecklistItem when its value is present. Returns null so
|
|
8091
|
+
* callers can filter absent fields out and only render populated rows.
|
|
8092
|
+
*/
|
|
8093
|
+
const infoRow = (t, key, params, testId, value) => {
|
|
8094
|
+
if (!value) return null;
|
|
8095
|
+
// 'no-icon' renders the label/value with no leading icon — these dense
|
|
8096
|
+
// metadata rows read as a plain key/value list, so an info dot per row is
|
|
8097
|
+
// just noise.
|
|
8098
|
+
return {
|
|
8099
|
+
type: 'no-icon',
|
|
8100
|
+
text: t(key, params),
|
|
8101
|
+
'data-testid': testId
|
|
8102
|
+
};
|
|
8103
|
+
};
|
|
8104
|
+
|
|
8105
|
+
/** External-link anchor rendered inline inside a Checklist item. */
|
|
8106
|
+
const ExternalLink = _ref => {
|
|
8107
|
+
let {
|
|
8108
|
+
href,
|
|
8109
|
+
children,
|
|
8110
|
+
'data-testid': testId
|
|
8111
|
+
} = _ref;
|
|
8112
|
+
return /*#__PURE__*/React__default.createElement("a", {
|
|
8113
|
+
href: href,
|
|
8114
|
+
target: "_blank",
|
|
8115
|
+
rel: "noopener noreferrer",
|
|
8116
|
+
"data-testid": testId
|
|
8117
|
+
}, children);
|
|
8118
|
+
};
|
|
8119
|
+
|
|
8120
|
+
/**
|
|
8121
|
+
* Build the five published-certificate sections (Validity, Certificate, Subject
|
|
8122
|
+
* identity, Mark evidence, Verification issues) from IPForensics
|
|
8123
|
+
* VmcPublishedCertificate + VmcPemEvidence data.
|
|
8124
|
+
*
|
|
8125
|
+
* All labels come from @redsift/signal-logic BIMI_KEYS via `t` so they remain
|
|
8126
|
+
* translatable. `now` is injected for deterministic humanized durations in
|
|
8127
|
+
* tests and stories.
|
|
8128
|
+
*/
|
|
8129
|
+
const buildPublishedCertificateSections = (cert, pem, t, now) => {
|
|
8130
|
+
var _cert$certifiedDomain, _cert$certifiedDomain2, _pem$errors;
|
|
8131
|
+
const sections = [];
|
|
8132
|
+
|
|
8133
|
+
// --- Validity ---
|
|
8134
|
+
const validFromText = humanizeValidFrom(cert.validFrom, now);
|
|
8135
|
+
const expiryText = humanizeExpiry(cert.expiry, now);
|
|
8136
|
+
const validityItems = [infoRow(t, 'card.bimi.vmc.cert-valid-from_md', {
|
|
8137
|
+
date: validFromText
|
|
8138
|
+
}, 'bimi-cert-valid-from', validFromText), infoRow(t, 'card.bimi.vmc.cert-expiry_md', {
|
|
8139
|
+
date: expiryText
|
|
8140
|
+
}, 'bimi-cert-expiry', expiryText)].filter(i => i !== null);
|
|
8141
|
+
if (validityItems.length) {
|
|
8142
|
+
sections.push({
|
|
8143
|
+
id: 'bimi-cert-validity',
|
|
8144
|
+
title: t('card.bimi.vmc.cert-section-validity'),
|
|
8145
|
+
items: validityItems,
|
|
8146
|
+
testId: 'bimi-cert-validity-section'
|
|
8147
|
+
});
|
|
8148
|
+
}
|
|
8149
|
+
|
|
8150
|
+
// --- Certificate ---
|
|
8151
|
+
const certItems = [];
|
|
8152
|
+
const issuerCommon = infoRow(t, 'card.bimi.vmc.cert-issuer-common-name_md', {
|
|
8153
|
+
issuerCommonName: cert.issuerCommonName
|
|
8154
|
+
}, 'bimi-cert-issuer-common-name', cert.issuerCommonName);
|
|
8155
|
+
if (issuerCommon) certItems.push(issuerCommon);
|
|
8156
|
+
const issuerOrg = infoRow(t, 'card.bimi.vmc.cert-issuer-organization_md', {
|
|
8157
|
+
issuerOrganization: cert.issuerOrganization
|
|
8158
|
+
}, 'bimi-cert-issuer-organization', cert.issuerOrganization);
|
|
8159
|
+
if (issuerOrg) certItems.push(issuerOrg);
|
|
8160
|
+
const issuerCountry = infoRow(t, 'card.bimi.vmc.cert-issuer-country_md', {
|
|
8161
|
+
issuerCountry: cert.issuerCountry
|
|
8162
|
+
}, 'bimi-cert-issuer-country', cert.issuerCountry);
|
|
8163
|
+
if (issuerCountry) certItems.push(issuerCountry);
|
|
8164
|
+
|
|
8165
|
+
// Certificate type row: a bold "Certificate type:" label with the VMC/CMC
|
|
8166
|
+
// value as an external-link badge. We interpolate a placeholder for the value
|
|
8167
|
+
// so the label markdown (**…**) parses correctly, then splice the linked
|
|
8168
|
+
// badge in where the value goes — only the value links, not the label.
|
|
8169
|
+
if (cert.markType) {
|
|
8170
|
+
const VALUE_TOKEN = '';
|
|
8171
|
+
const template = t('card.bimi.vmc.cert-type_md', {
|
|
8172
|
+
assertionMarkType: VALUE_TOKEN
|
|
8173
|
+
});
|
|
8174
|
+
const [before, after = ''] = template.split(VALUE_TOKEN);
|
|
8175
|
+
certItems.push({
|
|
8176
|
+
type: 'no-icon',
|
|
8177
|
+
'data-testid': 'bimi-cert-type',
|
|
8178
|
+
text: /*#__PURE__*/React__default.createElement("span", null, parseGlossaryMarkdown(before), /*#__PURE__*/React__default.createElement(ExternalLink, {
|
|
8179
|
+
href: CERT_TYPE_REFERENCE_URL,
|
|
8180
|
+
"data-testid": "bimi-cert-type-link"
|
|
8181
|
+
}, cert.markType), after && parseGlossaryMarkdown(after))
|
|
8182
|
+
});
|
|
8183
|
+
}
|
|
8184
|
+
|
|
8185
|
+
// Certified domains as chips with external links, comma-separated.
|
|
8186
|
+
const certifiedDomains = (_cert$certifiedDomain = (_cert$certifiedDomain2 = cert.certifiedDomains) === null || _cert$certifiedDomain2 === void 0 ? void 0 : _cert$certifiedDomain2.filter(d => !!d)) !== null && _cert$certifiedDomain !== void 0 ? _cert$certifiedDomain : [];
|
|
8187
|
+
if (certifiedDomains.length) {
|
|
8188
|
+
certItems.push({
|
|
8189
|
+
type: 'no-icon',
|
|
8190
|
+
'data-testid': 'bimi-cert-certified-domains',
|
|
8191
|
+
text: /*#__PURE__*/React__default.createElement("span", {
|
|
8192
|
+
"data-testid": "bimi-cert-certified-domains-chips"
|
|
8193
|
+
}, certifiedDomains.map((domain, idx) => /*#__PURE__*/React__default.createElement(React__default.Fragment, {
|
|
8194
|
+
key: domain
|
|
8195
|
+
}, idx > 0 && ', ', /*#__PURE__*/React__default.createElement(ExternalLink, {
|
|
8196
|
+
href: `https://${domain}`
|
|
8197
|
+
}, domain))))
|
|
8198
|
+
});
|
|
8199
|
+
}
|
|
8200
|
+
if (certItems.length) {
|
|
8201
|
+
sections.push({
|
|
8202
|
+
id: 'bimi-cert-certificate',
|
|
8203
|
+
title: t('card.bimi.vmc.cert-section-certificate'),
|
|
8204
|
+
items: certItems,
|
|
8205
|
+
testId: 'bimi-cert-certificate-section'
|
|
8206
|
+
});
|
|
8207
|
+
}
|
|
8208
|
+
|
|
8209
|
+
// --- Subject identity ---
|
|
8210
|
+
const jurisdiction = joinParts([cert.jurisdictionLocality, cert.jurisdictionStateOrProvince, cert.jurisdictionCountry]);
|
|
8211
|
+
const address = joinParts([cert.streetAddress, cert.locality, cert.stateOrProvince, cert.country]);
|
|
8212
|
+
const organizationIdentifier = cert.organizationIdentifier ? cert.organizationIdentifierScheme ? `${cert.organizationIdentifier} (${cert.organizationIdentifierScheme})` : cert.organizationIdentifier : undefined;
|
|
8213
|
+
const subjectItems = [infoRow(t, 'card.bimi.vmc.cert-serial-number_md', {
|
|
8214
|
+
serialNumber: cert.serialNumber
|
|
8215
|
+
}, 'bimi-cert-serial-number', cert.serialNumber), infoRow(t, 'card.bimi.vmc.cert-organization_md', {
|
|
8216
|
+
organization: cert.organization
|
|
8217
|
+
}, 'bimi-cert-organization', cert.organization), infoRow(t, 'card.bimi.vmc.cert-common-name_md', {
|
|
8218
|
+
commonName: cert.commonName
|
|
8219
|
+
}, 'bimi-cert-common-name', cert.commonName), infoRow(t, 'card.bimi.vmc.cert-business-category_md', {
|
|
8220
|
+
businessCategory: cert.businessCategory
|
|
8221
|
+
}, 'bimi-cert-business-category', cert.businessCategory), infoRow(t, 'card.bimi.vmc.cert-organization-identifier_md', {
|
|
8222
|
+
organizationIdentifier
|
|
8223
|
+
}, 'bimi-cert-organization-identifier', organizationIdentifier), infoRow(t, 'card.bimi.vmc.cert-legal-entity-identifier_md', {
|
|
8224
|
+
legalEntityIdentifier: cert.legalEntityIdentifier
|
|
8225
|
+
}, 'bimi-cert-legal-entity-identifier', cert.legalEntityIdentifier), infoRow(t, 'card.bimi.vmc.cert-jurisdiction_md', {
|
|
8226
|
+
jurisdiction
|
|
8227
|
+
}, 'bimi-cert-jurisdiction', jurisdiction), infoRow(t, 'card.bimi.vmc.cert-address_md', {
|
|
8228
|
+
address
|
|
8229
|
+
}, 'bimi-cert-address', address)].filter(i => i !== null);
|
|
8230
|
+
if (subjectItems.length) {
|
|
8231
|
+
sections.push({
|
|
8232
|
+
id: 'bimi-cert-subject-identity',
|
|
8233
|
+
title: t('card.bimi.vmc.cert-section-subject-identity'),
|
|
8234
|
+
items: subjectItems,
|
|
8235
|
+
testId: 'bimi-cert-subject-identity-section'
|
|
8236
|
+
});
|
|
8237
|
+
}
|
|
8238
|
+
|
|
8239
|
+
// --- Mark evidence ---
|
|
8240
|
+
const markItems = [infoRow(t, 'card.bimi.vmc.cert-trademark-registration_md', {
|
|
8241
|
+
trademarkRegistration: cert.trademarkRegistration
|
|
8242
|
+
}, 'bimi-cert-trademark-registration', cert.trademarkRegistration), infoRow(t, 'card.bimi.vmc.cert-trademark-office_md', {
|
|
8243
|
+
trademarkOfficeName: cert.trademarkOfficeName
|
|
8244
|
+
}, 'bimi-cert-trademark-office', cert.trademarkOfficeName), infoRow(t, 'card.bimi.vmc.cert-mark-type_md', {
|
|
8245
|
+
markType: cert.markType
|
|
8246
|
+
}, 'bimi-cert-mark-type', cert.markType), infoRow(t, 'card.bimi.vmc.cert-trademark-country_md', {
|
|
8247
|
+
trademarkCountryOrRegion: cert.trademarkCountryOrRegion
|
|
8248
|
+
}, 'bimi-cert-trademark-country', cert.trademarkCountryOrRegion)].filter(i => i !== null);
|
|
8249
|
+
if (markItems.length) {
|
|
8250
|
+
sections.push({
|
|
8251
|
+
id: 'bimi-cert-mark-evidence',
|
|
8252
|
+
title: t('card.bimi.vmc.cert-section-mark-evidence'),
|
|
8253
|
+
items: markItems,
|
|
8254
|
+
testId: 'bimi-cert-mark-evidence-section'
|
|
8255
|
+
});
|
|
8256
|
+
}
|
|
8257
|
+
|
|
8258
|
+
// --- Verification issues ---
|
|
8259
|
+
// Sourced from PEM evidence errors plus an ambiguous leaf-selection signal.
|
|
8260
|
+
const errorMessages = ((_pem$errors = pem === null || pem === void 0 ? void 0 : pem.errors) !== null && _pem$errors !== void 0 ? _pem$errors : []).map(e => typeof e === 'string' ? e : e === null || e === void 0 ? void 0 : e.message).filter(m => !!m);
|
|
8261
|
+
const isAmbiguous = (pem === null || pem === void 0 ? void 0 : pem.leafSelectionMethod) === 'AMBIGUOUS';
|
|
8262
|
+
const issueItems = [];
|
|
8263
|
+
if (isAmbiguous) {
|
|
8264
|
+
issueItems.push({
|
|
8265
|
+
type: 'warning',
|
|
8266
|
+
text: 'Ambiguous leaf certificate selection',
|
|
8267
|
+
'data-testid': 'bimi-cert-issue-ambiguous'
|
|
8268
|
+
});
|
|
8269
|
+
}
|
|
8270
|
+
errorMessages.forEach((message, idx) => {
|
|
8271
|
+
issueItems.push({
|
|
8272
|
+
type: 'warning',
|
|
8273
|
+
text: message,
|
|
8274
|
+
'data-testid': `bimi-cert-issue-${idx}`
|
|
8275
|
+
});
|
|
8276
|
+
});
|
|
8277
|
+
if (!issueItems.length) {
|
|
8278
|
+
issueItems.push({
|
|
8279
|
+
type: 'good',
|
|
8280
|
+
text: t('card.bimi.vmc.cert-no-issues-reported_md'),
|
|
8281
|
+
'data-testid': 'bimi-cert-no-issues'
|
|
8282
|
+
});
|
|
8283
|
+
}
|
|
8284
|
+
sections.push({
|
|
8285
|
+
id: 'bimi-cert-verification-issues',
|
|
8286
|
+
title: t('card.bimi.vmc.cert-section-verification-issues'),
|
|
8287
|
+
items: issueItems,
|
|
8288
|
+
testId: 'bimi-cert-verification-issues-section'
|
|
8289
|
+
});
|
|
8290
|
+
return sections;
|
|
8291
|
+
};
|
|
8292
|
+
|
|
7960
8293
|
const _excluded$2 = ["jmap", "onHeightChange", "useInvestigateColors", "isCollapsible", "areAllCollapsed", "onCollapseAll", "className"];
|
|
7961
8294
|
const COMPONENT_NAME$2 = 'SignalCardBimi';
|
|
7962
8295
|
const CLASSNAME$2 = 'redsift-signal-card-bimi';
|
|
@@ -7966,6 +8299,7 @@ const CLASSNAME$2 = 'redsift-signal-card-bimi';
|
|
|
7966
8299
|
* BIMI record validation, VMC certificate details, and SVG logo validation.
|
|
7967
8300
|
*/
|
|
7968
8301
|
const SignalCardBimi = /*#__PURE__*/forwardRef((props, ref) => {
|
|
8302
|
+
var _bimi$vmc;
|
|
7969
8303
|
const {
|
|
7970
8304
|
t
|
|
7971
8305
|
} = useSignalCardTranslation('investigate');
|
|
@@ -8024,31 +8358,77 @@ const SignalCardBimi = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
8024
8358
|
items
|
|
8025
8359
|
});
|
|
8026
8360
|
}, [adapterResult === null || adapterResult === void 0 ? void 0 : adapterResult.svgSection, bimi, isDeclinationToPublish]);
|
|
8361
|
+
const hasPublishedCertificate = !!(bimi !== null && bimi !== void 0 && (_bimi$vmc = bimi.vmc) !== null && _bimi$vmc !== void 0 && _bimi$vmc.publishedCertificate);
|
|
8027
8362
|
|
|
8028
8363
|
// Inject SVGLogo into VMC section (React-specific)
|
|
8029
8364
|
const vmcSection = useMemo(() => {
|
|
8030
|
-
var _bimi$
|
|
8365
|
+
var _bimi$vmc2;
|
|
8031
8366
|
if (isDeclinationToPublish || !(adapterResult !== null && adapterResult !== void 0 && adapterResult.vmcSection)) return null;
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
//
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
if (
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8367
|
+
let items = [...adapterResult.vmcSection.items];
|
|
8368
|
+
|
|
8369
|
+
// When the full published certificate is present, the new metadata sections
|
|
8370
|
+
// (below) supersede several legacy VMC rows with richer equivalents, so drop
|
|
8371
|
+
// the duplicated legacy rows to avoid showing each field twice (DS-93):
|
|
8372
|
+
// issuer → Certificate › Issuer
|
|
8373
|
+
// expiry → Validity › Expiry (matched by testid)
|
|
8374
|
+
// valid-for-domains → Certificate › Certified domains
|
|
8375
|
+
// trademark authority → Mark evidence › Trademark office
|
|
8376
|
+
// The legacy assertion-mark and VMC validity-status rows have no equivalent
|
|
8377
|
+
// in the new sections and are kept.
|
|
8378
|
+
if (hasPublishedCertificate) {
|
|
8379
|
+
const stripMd = s => s.replace(/[*`]/g, '').trim();
|
|
8380
|
+
// Label prefixes (value interpolated empty) of the legacy rows to suppress.
|
|
8381
|
+
const suppressedPrefixes = [t('card.bimi.vmc.issuer_md', {
|
|
8382
|
+
issuer: ''
|
|
8383
|
+
}), t('card.bimi.vmc.valid-for-domain_md', {
|
|
8384
|
+
domains: ''
|
|
8385
|
+
}), t('card.bimi.vmc.trademarkAuthority_md', {
|
|
8386
|
+
trademarkAuthority: ''
|
|
8387
|
+
})].map(stripMd).filter(Boolean);
|
|
8388
|
+
const suppressedTestIds = new Set(['vmc-expiration-valid', 'vmc-expiration-expired']);
|
|
8389
|
+
items = items.filter(item => {
|
|
8390
|
+
const testId = item['data-testid'];
|
|
8391
|
+
if (testId && suppressedTestIds.has(testId)) return false;
|
|
8392
|
+
if (typeof item.text === 'string') {
|
|
8393
|
+
const text = stripMd(item.text);
|
|
8394
|
+
if (suppressedPrefixes.some(prefix => text.startsWith(prefix))) return false;
|
|
8395
|
+
}
|
|
8396
|
+
return true;
|
|
8397
|
+
});
|
|
8398
|
+
}
|
|
8399
|
+
const logoSrc = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc2 = bimi.vmc) === null || _bimi$vmc2 === void 0 ? void 0 : _bimi$vmc2.logoSrc;
|
|
8400
|
+
if (logoSrc) {
|
|
8401
|
+
// Insert logo before the first 'no-icon' item (matching original helpers behavior)
|
|
8402
|
+
const noIconIdx = items.findIndex(item => item.type === 'no-icon');
|
|
8403
|
+
const svgItem = {
|
|
8404
|
+
text: /*#__PURE__*/React__default.createElement(SVGLogo$1, {
|
|
8405
|
+
svgUrl: logoSrc
|
|
8406
|
+
}),
|
|
8407
|
+
type: 'image'
|
|
8408
|
+
};
|
|
8409
|
+
if (noIconIdx >= 0) {
|
|
8410
|
+
items.splice(noIconIdx, 0, svgItem);
|
|
8411
|
+
} else {
|
|
8412
|
+
items.push(svgItem);
|
|
8413
|
+
}
|
|
8047
8414
|
}
|
|
8048
8415
|
return _objectSpread2(_objectSpread2({}, adapterResult.vmcSection), {}, {
|
|
8049
8416
|
items
|
|
8050
8417
|
});
|
|
8051
|
-
}, [adapterResult === null || adapterResult === void 0 ? void 0 : adapterResult.vmcSection, bimi, isDeclinationToPublish]);
|
|
8418
|
+
}, [adapterResult === null || adapterResult === void 0 ? void 0 : adapterResult.vmcSection, bimi, isDeclinationToPublish, hasPublishedCertificate, t]);
|
|
8419
|
+
|
|
8420
|
+
// Build the published-certificate metadata sections (VMC/CMC leaf identity,
|
|
8421
|
+
// mark evidence, verification issues). Only present when IPForensics resolved
|
|
8422
|
+
// a unique leaf; otherwise this is empty and the card degrades to the legacy
|
|
8423
|
+
// VMC section above (DS-93). `now` drives the humanized validity durations.
|
|
8424
|
+
const publishedCertSections = useMemo(() => {
|
|
8425
|
+
var _bimi$vmc3, _bimi$vmc4;
|
|
8426
|
+
if (isDeclinationToPublish) return [];
|
|
8427
|
+
const cert = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc3 = bimi.vmc) === null || _bimi$vmc3 === void 0 ? void 0 : _bimi$vmc3.publishedCertificate;
|
|
8428
|
+
if (!cert) return [];
|
|
8429
|
+
const pem = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc4 = bimi.vmc) === null || _bimi$vmc4 === void 0 ? void 0 : _bimi$vmc4.pem;
|
|
8430
|
+
return buildPublishedCertificateSections(cert, pem, t, new Date());
|
|
8431
|
+
}, [bimi, t, isDeclinationToPublish]);
|
|
8052
8432
|
const getTranslatedCaption = useCallback(caption => {
|
|
8053
8433
|
if (!caption) return undefined;
|
|
8054
8434
|
return t(EXTRACTION_CAPTION_KEYS[caption]);
|
|
@@ -8106,6 +8486,20 @@ const SignalCardBimi = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
8106
8486
|
testId: 'bimi-vmc-section'
|
|
8107
8487
|
});
|
|
8108
8488
|
}
|
|
8489
|
+
|
|
8490
|
+
// Full published-certificate metadata sections (DS-93). Rendered only when
|
|
8491
|
+
// vmc.publishedCertificate is present; otherwise the card keeps its legacy
|
|
8492
|
+
// VMC rendering above.
|
|
8493
|
+
publishedCertSections.forEach(section => {
|
|
8494
|
+
sections.push({
|
|
8495
|
+
id: section.id,
|
|
8496
|
+
title: section.title,
|
|
8497
|
+
content: /*#__PURE__*/React__default.createElement(Checklist$1, {
|
|
8498
|
+
items: section.items
|
|
8499
|
+
}),
|
|
8500
|
+
testId: section.testId
|
|
8501
|
+
});
|
|
8502
|
+
});
|
|
8109
8503
|
if (svgSection) {
|
|
8110
8504
|
sections.push({
|
|
8111
8505
|
id: 'safeSVG',
|