export class SignedExchangeInfoView extends UI.VBox{constructor(request){super();const signedExchangeInfo=request.signedExchangeInfo();console.assert(signedExchangeInfo);this.registerRequiredCSS('network/signedExchangeInfoView.css');this.element.classList.add('signed-exchange-info-view');const root=new UI.TreeOutlineInShadow();root.registerRequiredCSS('network/signedExchangeInfoTree.css');root.element.classList.add('signed-exchange-info-tree');root.setFocusable(false);root.makeDense();root.expandTreeElementsWhenArrowing=true;this.element.appendChild(root.element);const errorFieldSetMap=new Map();if(signedExchangeInfo.errors&&signedExchangeInfo.errors.length){const errorMessagesCategory=new Category(root,Common.UIString('Errors'));for(const error of signedExchangeInfo.errors){const fragment=createDocumentFragment();fragment.appendChild(UI.Icon.create('smallicon-error','prompt-icon'));fragment.createChild('div','error-log').textContent=error.message;errorMessagesCategory.createLeaf(fragment);if(error.errorField){let errorFieldSet=errorFieldSetMap.get(error.signatureIndex);if(!errorFieldSet){errorFieldSet=new Set();errorFieldSetMap.set(error.signatureIndex,errorFieldSet);}
errorFieldSet.add(error.errorField);}}}
const titleElement=createDocumentFragment();titleElement.createChild('div','header-name').textContent=Common.UIString('Signed HTTP exchange');const learnMoreNode=UI.XLink.create('https://github.com/WICG/webpackage',Common.UIString('Learn\xa0more'),'header-toggle');titleElement.appendChild(learnMoreNode);const headerCategory=new Category(root,titleElement);if(signedExchangeInfo.header){const header=signedExchangeInfo.header;const redirectDestination=request.redirectDestination();const requestURLElement=this._formatHeader(Common.UIString('Request URL'),header.requestUrl);if(redirectDestination){const viewRequestLink=Components.Linkifier.linkifyRevealable(redirectDestination,'View request');viewRequestLink.classList.add('header-toggle');requestURLElement.appendChild(viewRequestLink);}
headerCategory.createLeaf(requestURLElement);headerCategory.createLeaf(this._formatHeader(Common.UIString('Response code'),header.responseCode+''));headerCategory.createLeaf(this._formatHeader(Common.UIString('Header integrity hash'),header.headerIntegrity));this._responseHeadersItem=headerCategory.createLeaf(this._formatHeader(Common.UIString('Response headers'),''));const responseHeaders=header.responseHeaders;for(const name in responseHeaders){const headerTreeElement=new UI.TreeElement(this._formatHeader(name,responseHeaders[name]));headerTreeElement.selectable=false;this._responseHeadersItem.appendChild(headerTreeElement);}
this._responseHeadersItem.expand();for(let i=0;i<header.signatures.length;++i){const errorFieldSet=errorFieldSetMap.get(i)||new Set();const signature=header.signatures[i];const signatureCategory=new Category(root,Common.UIString('Signature'));signatureCategory.createLeaf(this._formatHeader(Common.UIString('Label'),signature.label));signatureCategory.createLeaf(this._formatHeaderForHexData(Common.UIString('Signature'),signature.signature,errorFieldSet.has(Protocol.Network.SignedExchangeErrorField.SignatureSig)));if(signature.certUrl){const certURLElement=this._formatHeader(Common.UIString('Certificate URL'),signature.certUrl,errorFieldSet.has(Protocol.Network.SignedExchangeErrorField.SignatureCertUrl));if(signature.certificates){const viewCertLink=certURLElement.createChild('span','devtools-link header-toggle');viewCertLink.textContent=Common.UIString('View certificate');viewCertLink.addEventListener('click',Host.InspectorFrontendHost.showCertificateViewer.bind(null,signature.certificates),false);}
signatureCategory.createLeaf(certURLElement);}
signatureCategory.createLeaf(this._formatHeader(Common.UIString('Integrity'),signature.integrity,errorFieldSet.has(Protocol.Network.SignedExchangeErrorField.SignatureIntegrity)));if(signature.certSha256){signatureCategory.createLeaf(this._formatHeaderForHexData(Common.UIString('Certificate SHA256'),signature.certSha256,errorFieldSet.has(Protocol.Network.SignedExchangeErrorField.SignatureCertSha256)));}
signatureCategory.createLeaf(this._formatHeader(Common.UIString('Validity URL'),signature.validityUrl,errorFieldSet.has(Protocol.Network.SignedExchangeErrorField.SignatureValidityUrl)));signatureCategory.createLeaf().title=this._formatHeader(Common.UIString('Date'),new Date(1000*signature.date).toUTCString(),errorFieldSet.has(Protocol.Network.SignedExchangeErrorField.SignatureTimestamps));signatureCategory.createLeaf().title=this._formatHeader(Common.UIString('Expires'),new Date(1000*signature.expires).toUTCString(),errorFieldSet.has(Protocol.Network.SignedExchangeErrorField.SignatureTimestamps));}}
if(signedExchangeInfo.securityDetails){const securityDetails=signedExchangeInfo.securityDetails;const securityCategory=new Category(root,Common.UIString('Certificate'));securityCategory.createLeaf(this._formatHeader(Common.UIString('Subject'),securityDetails.subjectName));securityCategory.createLeaf(this._formatHeader(Common.UIString('Valid from'),new Date(1000*securityDetails.validFrom).toUTCString()));securityCategory.createLeaf(this._formatHeader(Common.UIString('Valid until'),new Date(1000*securityDetails.validTo).toUTCString()));securityCategory.createLeaf(this._formatHeader(Common.UIString('Issuer'),securityDetails.issuer));}}
_formatHeader(name,value,highlighted){const fragment=createDocumentFragment();const nameElement=fragment.createChild('div','header-name');nameElement.textContent=name+': ';fragment.createChild('span','header-separator');const valueElement=fragment.createChild('div','header-value source-code');valueElement.textContent=value;if(highlighted){nameElement.classList.add('error-field');valueElement.classList.add('error-field');}
return fragment;}
_formatHeaderForHexData(name,value,highlighted){const fragment=createDocumentFragment();const nameElement=fragment.createChild('div','header-name');nameElement.textContent=name+': ';fragment.createChild('span','header-separator');const valueElement=fragment.createChild('div','header-value source-code hex-data');valueElement.textContent=value.replace(/(.{2})/g,'$1 ');if(highlighted){nameElement.classList.add('error-field');valueElement.classList.add('error-field');}
return fragment;}}
export class Category extends UI.TreeElement{constructor(root,title){super(title,true);this.selectable=false;this.toggleOnClick=true;this.expanded=true;root.appendChild(this);}
createLeaf(title){const leaf=new UI.TreeElement(title);leaf.selectable=false;this.appendChild(leaf);return leaf;}}