diff --git a/.github/workflows/auto-publish.yml b/.github/workflows/auto-publish.yml new file mode 100644 index 0000000..810c027 --- /dev/null +++ b/.github/workflows/auto-publish.yml @@ -0,0 +1,19 @@ +name: CI +on: + pull_request: {} + push: + branches: [main] +jobs: + main: + name: Build, Validate and Deploy + runs-on: ubuntu-20.04 + permissions: + contents: write + steps: + - uses: actions/checkout@v3 + - uses: w3c/spec-prod@v2 + with: + TOOLCHAIN: bikeshed + GH_PAGES_BRANCH: gh-pages + SOURCE: docs/spec.bs + DESTINATION: index.html diff --git a/README.md b/README.md index 7059569..d406af9 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,4 @@ const attestation = await navigator.getEnvironmentIntegrity("..."); The [explainer](./explainer.md) goes gives a high level overview of the proposal. -The [spec](./docs/spec) currently describes how this is being prototyped in Chromium. +The [spec](./docs/spec.bs) currently describes how this is being prototyped in Chromium. diff --git a/docs/spec/index.bs b/docs/spec.bs similarity index 99% rename from docs/spec/index.bs rename to docs/spec.bs index 8b6d616..e6aad03 100644 --- a/docs/spec/index.bs +++ b/docs/spec.bs @@ -71,6 +71,7 @@ stores state in the [=Integrity verdict=] that can be used for cross site tracki ## {{AttesterConnection}} ## {#attester-connection} + [Exposed=Window] interface AttesterConnection { ArrayBuffer getAttestation(DOMString contentBinding); }; @@ -111,6 +112,7 @@ stores state in the [=Integrity verdict=] that can be used for cross site tracki ## {{EnvironmentIntegrity}} ## {#environment-integrity} <xmp class="idl"> + [Exposed=Window] interface EnvironmentIntegrity { readonly attribute ArrayBuffer attestationToken; DOMString encode(); diff --git a/docs/spec/index.html b/docs/spec/index.html deleted file mode 100644 index fed1f11..0000000 --- a/docs/spec/index.html +++ /dev/null @@ -1,3176 +0,0 @@ -<!doctype html><html lang="en"> - <head> - <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> - <title>Web Environment Integrity</title> - <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport"> -<style data-fill-with="stylesheet">/****************************************************************************** - * Style sheet for the W3C specifications * - * - * Special classes handled by this style sheet include: - * - * Indices - * - .toc for the Table of Contents (<ol class="toc">) - * + <span class="secno"> for the section numbers - * - #toc for the Table of Contents (<nav id="toc">) - * - ul.index for Indices (<a href="#ref">term</a><span>, in § N.M</span>) - * - table.index for Index Tables (e.g. for properties or elements) - * - * Structural Markup - * - table.data for general data tables - * -> use 'scope' attribute, <colgroup>, <thead>, and <tbody> for best results ! - * -> use <table class='complex data'> for extra-complex tables - * -> use <td class='long'> for paragraph-length cell content - * -> use <td class='pre'> when manual line breaks/indentation would help readability - * - dl.switch for switch statements - * - ol.algorithm for algorithms (helps to visualize nesting) - * - .figure and .caption (HTML4) and figure and figcaption (HTML5) - * -> .sidefigure for right-floated figures - * - ins/del - * -> ins/del.c### for candidate and proposed changes (amendments) - * - * Code - * - pre and code - * - * Special Sections - * - .note for informative notes (div, p, span, aside, details) - * - .example for informative examples (div, p, pre, span) - * - .issue for issues (div, p, span) - * - .advisement for loud normative statements (div, p, strong) - * - .annoying-warning for spec obsoletion notices (div, aside, details) - * - .correction for "candidate corrections" (div, aside, details, section) - * - .addition for "candidate additions" (div, aside, details, section) - * - .correction.proposed for "proposed corrections" (div, aside, details, section) - * - .addition.proposed for "proposed additions" (div, aside, details, section) - * - * Definition Boxes - * - pre.def for WebIDL definitions - * - table.def for tables that define other entities (e.g. CSS properties) - * - dl.def for definition lists that define other entitles (e.g. HTML elements) - * - * Numbering - * - .secno for section numbers in .toc and headings (<span class='secno'>3.2</span>) - * - .marker for source-inserted example/figure/issue numbers (<span class='marker'>Issue 4</span>) - * - ::before styled for CSS-generated issue/example/figure numbers: - * -> Documents wishing to use this only need to add - * figcaption::before, - * .caption::before { content: "Figure " counter(figure) " "; } - * .example::before { content: "Example " counter(example) " "; } - * .issue::before { content: "Issue " counter(issue) " "; } - * - * Header Stuff (ignore, just don't conflict with these classes) - * - .head for the header - * - .copyright for the copyright - * - * Outdated warning for old specs - * - * Miscellaneous - * - .overlarge for things that should be as wide as possible, even if - * that overflows the body text area. This can be used on an item or - * on its container, depending on the effect desired. - * Note that this styling basically doesn't help at all when printing, - * since A4 paper isn't much wider than the max-width here. - * It's better to design things to fit into a narrower measure if possible. - * - * - js-added ToC jump links (see fixup.js) - * - ******************************************************************************/ - -/* color variables included separately for reliability */ - -/******************************************************************************/ -/* Body */ -/******************************************************************************/ - - html { - } - - body { - counter-reset: example figure issue; - - /* Layout */ - max-width: 50em; /* limit line length to 50em for readability */ - margin: 0 auto; /* center text within page */ - padding: 1.6em 1.5em 2em 50px; /* assume 16px font size for downlevel clients */ - padding: 1.6em 1.5em 2em calc(26px + 1.5em); /* leave space for status flag */ - - /* Typography */ - line-height: 1.5; - font-family: sans-serif; - widows: 2; - orphans: 2; - word-wrap: break-word; - overflow-wrap: break-word; - hyphens: auto; - - color: black; - color: var(--text); - background: white top left fixed no-repeat; - background: var(--bg) top left fixed no-repeat; - background-size: 25px auto; - } - - -/******************************************************************************/ -/* Front Matter & Navigation */ -/******************************************************************************/ - -/** Header ********************************************************************/ - - div.head { margin-bottom: 1em; } - div.head hr { border-style: solid; } - - div.head h1 { - font-weight: bold; - margin: 0 0 .1em; - font-size: 220%; - } - - div.head h2 { margin-bottom: 1.5em;} - -/** W3C Logo ******************************************************************/ - - .head .logo { - float: right; - margin: 0.4rem 0 0.2rem .4rem; - } - - .head img[src*="logos/W3C"] { - display: block; - border: solid #1a5e9a; - border: solid var(--logo-bg); - border-width: .65rem .7rem .6rem; - border-radius: .4rem; - background: #1a5e9a; - background: var(--logo-bg); - color: white; - color: var(--logo-text); - font-weight: bold; - } - - .head a:hover > img[src*="logos/W3C"], - .head a:focus > img[src*="logos/W3C"] { - opacity: .8; - } - - .head a:active > img[src*="logos/W3C"] { - background: #c00; - background: var(--logo-active-bg); - border-color: #c00; - border-color: var(--logo-active-bg); - } - - /* see also additional rules in Link Styling section */ - -/** Copyright *****************************************************************/ - - p.copyright, - p.copyright small { font-size: small; } - -/** Back to Top / ToC Toggle **************************************************/ - - @media print { - #toc-nav { - display: none; - } - } - @media not print { - #toc-nav { - position: fixed; - z-index: 3; - bottom: 0; left: 0; - margin: 0; - min-width: 1.33em; - border-top-right-radius: 2rem; - box-shadow: 0 0 2px; - font-size: 1.5em; - } - #toc-nav > a { - display: block; - white-space: nowrap; - - height: 1.33em; - padding: .1em 0.3em; - margin: 0; - - box-shadow: 0 0 2px; - border: none; - border-top-right-radius: 1.33em; - - color: #707070; - color: var(--tocnav-normal-text); - background: white; - background: var(--tocnav-normal-bg); - } - #toc-nav > a:hover, - #toc-nav > a:focus { - color: black; - color: var(--tocnav-hover-text); - background: #f8f8f8; - background: var(--tocnav-hover-bg); - } - #toc-nav > a:active { - color: #c00; - color: var(--tocnav-active-text); - background: white; - background: var(--tocnav-active-bg); - } - - #toc-nav > #toc-jump { - padding-bottom: 2em; - margin-bottom: -1.9em; - } - - /* statusbar gets in the way on keyboard focus; remove once browsers fix */ - #toc-nav > a[href="#toc"]:not(:hover):focus:last-child { - padding-bottom: 1.5rem; - } - - #toc-nav:not(:hover) > a:not(:focus) > span + span { - /* Ideally this uses :focus-within on #toc-nav */ - display: none; - } - #toc-nav > a > span + span { - padding-right: 0.2em; - } - } - -/** ToC Sidebar ***************************************************************/ - - /* Floating sidebar */ - @media screen { - body.toc-sidebar #toc { - position: fixed; - top: 0; bottom: 0; - left: 0; - width: 23.5em; - max-width: 80%; - max-width: calc(100% - 2em - 26px); - overflow: auto; - padding: 0 1em; - padding-left: 42px; - padding-left: calc(1em + 26px); - color: black; - color: var(--tocsidebar-text); - background: inherit; - background-color: #f7f8f9; - background-color: var(--tocsidebar-bg); - z-index: 1; - box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset; - box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset; - } - body.toc-sidebar #toc h2 { - margin-top: .8rem; - font-variant: small-caps; - font-variant: all-small-caps; - text-transform: lowercase; - font-weight: bold; - color: gray; - color: hsla(203,20%,40%,.7); - color: var(--tocsidebar-heading-text); - } - body.toc-sidebar #toc-jump:not(:focus) { - width: 0; - height: 0; - padding: 0; - position: absolute; - overflow: hidden; - } - } - /* Hide main scroller when only the ToC is visible anyway */ - @media screen and (max-width: 28em) { - body.toc-sidebar { - overflow: hidden; - } - } - - /* Sidebar with its own space */ - @media screen and (min-width: 78em) { - body:not(.toc-inline) #toc { - position: fixed; - top: 0; bottom: 0; - left: 0; - width: 23.5em; - overflow: auto; - padding: 0 1em; - padding-left: 42px; - padding-left: calc(1em + 26px); - color: black; - color: var(--tocsidebar-text); - background: inherit; - background-color: #f7f8f9; - background-color: var(--tocsidebar-bg); - z-index: 1; - box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset; - box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset; - } - body:not(.toc-inline) #toc h2 { - margin-top: .8rem; - font-variant: small-caps; - font-variant: all-small-caps; - text-transform: lowercase; - font-weight: bold; - color: gray; - color: hsla(203,20%,40%,.7); - color: var(--tocsidebar-heading-text); - } - - body:not(.toc-inline) { - padding-left: 29em; - } - /* See also Overflow section at the bottom */ - - body:not(.toc-inline) #toc-jump:not(:focus) { - width: 0; - height: 0; - padding: 0; - position: absolute; - overflow: hidden; - } - } - @media screen and (min-width: 90em) { - body:not(.toc-inline) { - margin: 0 4em; - } - } - -/******************************************************************************/ -/* Sectioning */ -/******************************************************************************/ - -/** Headings ******************************************************************/ - - h1, h2, h3, h4, h5, h6, dt { - page-break-after: avoid; - page-break-inside: avoid; - font: 100% sans-serif; /* Reset all font styling to clear out UA styles */ - font-family: inherit; /* Inherit the font family. */ - line-height: 1.2; /* Keep wrapped headings compact */ - hyphens: manual; /* Hyphenated headings look weird */ - } - - h2, h3, h4, h5, h6 { - margin-top: 3rem; - } - - h1, h2, h3 { - color: #005A9C; - color: var(--heading-text); - } - - h1 { font-size: 170%; } - h2 { font-size: 140%; } - h3 { font-size: 120%; } - h4 { font-weight: bold; } - h5 { font-style: italic; } - h6 { font-variant: small-caps; } - dt { font-weight: bold; } - -/** Subheadings ***************************************************************/ - - h1 + h2, - #profile-and-date { - /* #profile-and-date is a subtitle in an H2 under the H1 */ - margin-top: 0; - } - h2 + h3, - h3 + h4, - h4 + h5, - h5 + h6 { - margin-top: 1.2em; /* = 1 x line-height */ - } - -/** Section divider ***********************************************************/ - - :not(.head) > :not(.head) + hr { - font-size: 1.5em; - text-align: center; - margin: 1em auto; - height: auto; - color: black; - color: var(--hr-text); - border: transparent solid 0; - background: transparent; - } - :not(.head) > hr::before { - content: "\2727\2003\2003\2727\2003\2003\2727"; - } - -/******************************************************************************/ -/* Paragraphs and Lists */ -/******************************************************************************/ - - p { - margin: 1em 0; - } - - dd > p:first-child, - li > p:first-child { - margin-top: 0; - } - - ul, ol { - margin-left: 0; - padding-left: 2em; - } - - li { - margin: 0.25em 0 0.5em; - padding: 0; - } - - dl dd { - margin: 0 0 .5em 2em; - } - - .head dd + dd { /* compact for header */ - margin-top: -.5em; - } - - /* Style for algorithms */ - ol.algorithm ol:not(.algorithm), - .algorithm > ol ol:not(.algorithm) { - border-left: 0.5em solid #DEF; - border-left: 0.5em solid var(--algo-border); - } - - /* Put nice boxes around each algorithm. */ - [data-algorithm]:not(.heading) { - padding: .5em; - border: thin solid #ddd; - border: thin solid var(--algo-border); - border-radius: .5em; - margin: .5em calc(-0.5em - 1px); - } - [data-algorithm]:not(.heading) > :first-child { - margin-top: 0; - } - [data-algorithm]:not(.heading) > :last-child { - margin-bottom: 0; - } - - /* Style for switch/case <dl>s */ - dl.switch > dd > ol.only, - dl.switch > dd > .only > ol { - margin-left: 0; - } - dl.switch > dd > ol.algorithm, - dl.switch > dd > .algorithm > ol { - margin-left: -2em; - } - dl.switch { - padding-left: 2em; - } - dl.switch > dt { - text-indent: -1.5em; - margin-top: 1em; - } - dl.switch > dt + dt { - margin-top: 0; - } - dl.switch > dt::before { - content: '\21AA'; - padding: 0 0.5em 0 0; - display: inline-block; - width: 1em; - text-align: right; - line-height: 0.5em; - } - -/** Terminology Markup ********************************************************/ - - -/******************************************************************************/ -/* Inline Markup */ -/******************************************************************************/ - -/** Terminology Markup ********************************************************/ - dfn { /* Defining instance */ - font-weight: bolder; - } - a > i { /* Instance of term */ - font-style: normal; - } - dt dfn code, code.idl { - font-size: inherit; - } - dfn var { - font-style: normal; - } - -/** Change Marking ************************************************************/ - - del { - color: #aa0000; - color: var(--del-text); - background: transparent; - background: var(--del-bg); - text-decoration: line-through; - } - ins { - color: #006100; - color: var(--ins-text); - background: transparent; - background: var(--ins-bg); - text-decoration: underline; - } - - /* for amendments (candidate/proposed changes) */ - - .amendment ins, .correction ins, .addition ins, - ins[class^=c] { - text-decoration-style: dotted; - } - .amendment del, .correction del, .addition del, - del[class^=c] { - text-decoration-style: dotted; - } - .amendment.proposed ins, .correction.proposed ins, .addition.proposed ins, - ins[class^=c].proposed { - text-decoration-style: double; - } - .amendment.proposed del, .correction.proposed del, .addition.proposed del, - del[class^=c].proposed { - text-decoration-style: double; - } - -/** Miscellaneous improvements to inline formatting ***************************/ - - sup { - vertical-align: super; - font-size: 80% - } - -/******************************************************************************/ -/* Code */ -/******************************************************************************/ - -/** General monospace/pre rules ***********************************************/ - - pre, code, samp { - font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace; - font-size: .9em; - hyphens: none; - text-transform: none; - text-align: left; - text-align: start; - font-variant: normal; - orphans: 3; - widows: 3; - page-break-before: avoid; - } - pre code, - code code { - font-size: 100%; - } - - pre { - margin-top: 1em; - margin-bottom: 1em; - overflow: auto; - } - -/** Inline Code fragments *****************************************************/ - - /* Do something nice. */ - -/******************************************************************************/ -/* Links */ -/******************************************************************************/ - -/** General Hyperlinks ********************************************************/ - - /* We hyperlink a lot, so make it less intrusive */ - a[href] { - color: #034575; - color: var(--a-normal-text); - text-decoration: underline #707070; - text-decoration: underline var(--a-normal-underline); - text-decoration-skip-ink: none; - } - a:visited { - color: #034575; - color: var(--a-visited-text); - text-decoration-color: #bbb; - text-decoration-color: var(--a-visited-underline); - } - - /* Indicate interaction with the link */ - a[href]:focus, - a[href]:hover { - text-decoration-thickness: 2px; - } - a[href]:active { - color: #c00; - color: var(--a-active-text); - text-decoration-color: #c00; - text-decoration-color: var(--a-active-underline); - } - - /* Backout above styling for W3C logo */ - .head .logo, - .head .logo a { - border: none; - text-decoration: none; - background: transparent; - } - -/******************************************************************************/ -/* Images */ -/******************************************************************************/ - - img { - border-style: none; - } - - img, svg { - /* Intentionally not color-scheme aware. */ - background: white; - } - - /* For autogen numbers, add - .caption::before, figcaption::before { content: "Figure " counter(figure) ". "; } - */ - - figure, .figure, .sidefigure { - page-break-inside: avoid; - text-align: center; - margin: 2.5em 0; - } - .figure img, .sidefigure img, figure img, - .figure object, .sidefigure object, figure object { - max-width: 100%; - margin: auto; - height: auto; - } - .figure pre, .sidefigure pre, figure pre { - text-align: left; - display: table; - margin: 1em auto; - } - .figure table, figure table { - margin: auto; - } - @media screen and (min-width: 20em) { - .sidefigure { - float: right; - width: 50%; - margin: 0 0 0.5em 0.5em; - } - } - .caption, figcaption, caption { - font-style: italic; - font-size: 90%; - } - .caption::before, figcaption::before, figcaption > .marker { - font-weight: bold; - } - .caption, figcaption { - counter-increment: figure; - } - - /* DL list is indented 2em, but figure inside it is not */ - dd > .figure, dd > figure { margin-left: -2em; } - -/******************************************************************************/ -/* Colored Boxes */ -/******************************************************************************/ - - .issue, .note, .example, .assertion, .advisement, blockquote, - .amendment, .correction, .addition { - margin: 1em auto; - padding: .5em; - border: .5em; - border-left-style: solid; - page-break-inside: avoid; - } - span.issue, span.note { - padding: .1em .5em .15em; - border-right-style: solid; - } - - blockquote > :first-child, - .note > p:first-child, - .issue > p:first-child, - .amendment > p:first-child, - .correction > p:first-child, - .addition > p:first-child { - margin-top: 0; - } - blockquote > :last-child, - .note > p:last-child, - .issue > p:last-child, - .amendment > p:last-child, - .correction > p:last-child, - .addition > p:last-child { - margin-bottom: 0; - } - - - .issue::before, .issue > .marker, - .example::before, .example > .marker, - .note::before, .note > .marker, - details.note > summary > .marker, - .amendment::before, .amendment > .marker, - details.amendment > summary > .marker, - .addition::before, .addition > .marker, - addition.amendment > summary > .marker, - .correction::before, .correction > .marker, - correction.amendment > summary > .marker - { - text-transform: uppercase; - padding-right: 1em; - } - - .example::before, .example > .marker { - display: block; - padding-right: 0em; - } - -/** Blockquotes ***************************************************************/ - - blockquote { - border-color: silver; - border-color: var(--blockquote-border); - background: transparent; - background: var(--blockquote-bg); - color: currentcolor; - color: var(--blockquote-text); - } - -/** Open issue ****************************************************************/ - - .issue { - border-color: #e05252; - border-color: var(--issue-border); - background: #fbe9e9; - background: var(--issue-bg); - color: black; - color: var(--issue-text); - counter-increment: issue; - overflow: auto; - } - .issue::before, .issue > .marker { - color: #831616; - color: var(--issueheading-text); - } - /* Add .issue::before { content: "Issue " counter(issue) " "; } for autogen numbers, - or use class="marker" to mark up the issue number in source. */ - -/** Example *******************************************************************/ - - .example { - border-color: #e0cb52; - border-color: var(--example-border); - background: #fcfaee; - background: var(--example-bg); - color: black; - color: var(--example-text); - counter-increment: example; - overflow: auto; - clear: both; - } - .example::before, .example > .marker { - color: #574b0f; - color: var(--exampleheading-text); - } - /* Add .example::before { content: "Example " counter(example) " "; } for autogen numbers, - or use class="marker" to mark up the example number in source. */ - -/** Non-normative Note ********************************************************/ - - .note { - border-color: #52e052; - border-color: var(--note-border); - background: #e9fbe9; - background: var(--note-bg); - color: black; - color: var(--note-text); - overflow: auto; - } - - .note::before, .note > .marker, - details.note > summary { - color: hsl(120, 70%, 30%); - color: var(--noteheading-text); - } - /* Add .note::before { content: "Note "; } for autogen label, - or use class="marker" to mark up the label in source. */ - - details.note[open] > summary { - border-bottom: 1px silver solid; - border-bottom: 1px var(--notesummary-underline) solid; - } - -/** Assertion Box *************************************************************/ - /* for assertions in algorithms */ - - .assertion { - border-color: #AAA; - border-color: var(--assertion-border); - background: #EEE; - background: var(--assertion-bg); - color: black; - color: var(--assertion-text); - } - -/** Advisement Box ************************************************************/ - /* for attention-grabbing normative statements */ - - .advisement { - border-color: orange; - border-color: var(--advisement-border); - border-style: none solid; - background: #fec; - background: var(--advisement-bg); - color: black; - color: var(--advisement-text); - } - strong.advisement { - display: block; - text-align: center; - } - .advisement::before, .advisement > .marker { - color: #b35f00; - color: var(--advisementheading-text); - } - -/** Amendment Box *************************************************************/ - - .amendment, .correction, .addition { - border-color: #330099; - border-color: var(--amendment-border); - background: #F5F0FF; - background: var(--amendment-bg); - color: black; - color: var(--amendment-text); - } - .amendment.proposed, .correction.proposed, .addition.proposed { - border-style: solid; - border-block-width: 0.25em; - } - .amendment::before, .amendment > .marker, - details.amendment > summary::before, details.amendment > summary > .marker, - .correction::before, .correction > .marker, - details.correction > summary::before, details.correction > summary > .marker, - .addition::before, .addition > .marker, - details.addition > summary::before, details.addition > summary > .marker { - color: #220066; - color: var(--amendmentheading-text); - } - .amendment.proposed::before, .amendment.proposed > .marker, - details.amendment.proposed > summary::before, details.amendment.proposed > summary > .marker, - .correction.proposed::before, .correction.proposed > .marker, - details.correction.proposed > summary::before, details.correction.proposed > summary > .marker, - .addition.proposed::before, .addition.proposed > .marker, - details.addition.proposed > summary::before, details.addition.proposed > summary > .marker { - font-weight: bold; - } - -/** Spec Obsoletion Notice ****************************************************/ - /* obnoxious obsoletion notice for older/abandoned specs. */ - - details { - display: block; - } - summary { - font-weight: bolder; - } - - .annoying-warning:not(details), - details.annoying-warning:not([open]) > summary, - details.annoying-warning[open] { - background: hsla(40,100%,50%,0.95); - background: var(--warning-bg); - color: black; - color: var(--warning-text); - padding: .75em 1em; - border: red; - border: var(--warning-border); - border-style: solid none; - box-shadow: 0 2px 8px black; - text-align: center; - } - .annoying-warning :last-child { - margin-bottom: 0; - } - -@media not print { - details.annoying-warning[open] { - position: fixed; - left: 0; - right: 0; - bottom: 2em; - z-index: 1000; - } -} - - details.annoying-warning:not([open]) > summary { - text-align: center; - } - -/** Entity Definition Boxes ***************************************************/ - - .def { - padding: .5em 1em; - background: #def; - background: var(--def-bg); - margin: 1.2em 0; - border-left: 0.5em solid #8ccbf2; - border-left: 0.5em solid var(--def-border); - color: black; - color: var(--def-text); - } - -/******************************************************************************/ -/* Tables */ -/******************************************************************************/ - - th, td { - text-align: left; - text-align: start; - } - -/** Property/Descriptor Definition Tables *************************************/ - - table.def { - /* inherits .def box styling, see above */ - width: 100%; - border-spacing: 0; - } - - table.def td, - table.def th { - padding: 0.5em; - vertical-align: baseline; - border-bottom: 1px solid #bbd7e9; - border-bottom: 1px solid var(--defrow-border); - } - - table.def > tbody > tr:last-child th, - table.def > tbody > tr:last-child td { - border-bottom: 0; - } - - table.def th { - font-style: italic; - font-weight: normal; - padding-left: 1em; - width: 3em; - } - - /* For when values are extra-complex and need formatting for readability */ - table td.pre { - white-space: pre-wrap; - } - - /* A footnote at the bottom of a def table */ - table.def td.footnote { - padding-top: 0.6em; - } - table.def td.footnote::before { - content: " "; - display: block; - height: 0.6em; - width: 4em; - border-top: thin solid; - } - -/** Data tables (and properly marked-up index tables) *************************/ - /* - <table class="data"> highlights structural relationships in a table - when correct markup is used (e.g. thead/tbody, th vs. td, scope attribute) - - Use class="complex data" for particularly complicated tables -- - (This will draw more lines: busier, but clearer.) - - Use class="long" on table cells with paragraph-like contents - (This will adjust text alignment accordingly.) - Alternately use class="longlastcol" on tables, to have the last column assume "long". - */ - - table { - word-wrap: normal; - overflow-wrap: normal; - hyphens: manual; - } - - table.data, - table.index { - margin: 1em auto; - border-collapse: collapse; - border: hidden; - width: 100%; - } - table.data caption, - table.index caption { - max-width: 50em; - margin: 0 auto 1em; - } - - table.data td, table.data th, - table.index td, table.index th { - padding: 0.5em 1em; - border-width: 1px; - border-color: silver; - border-color: var(--datacell-border); - border-top-style: solid; - } - - table.data thead td:empty { - padding: 0; - border: 0; - } - - table.data thead, - table.index thead, - table.data tbody, - table.index tbody { - border-bottom: 2px solid; - } - - table.data colgroup, - table.index colgroup { - border-left: 2px solid; - } - - table.data tbody th:first-child, - table.index tbody th:first-child { - border-right: 2px solid; - border-top: 1px solid silver; - border-top: 1px solid var(--datacell-border); - padding-right: 1em; - } - - table.data th[colspan], - table.data td[colspan] { - text-align: center; - } - - table.complex.data th, - table.complex.data td { - border: 1px solid silver; - border: 1px solid var(--datacell-border); - text-align: center; - } - - table.data.longlastcol td:last-child, - table.data td.long { - vertical-align: baseline; - text-align: left; - } - - table.data img { - vertical-align: middle; - } - - -/* -Alternate table alignment rules - - table.data, - table.index { - text-align: center; - } - - table.data thead th[scope="row"], - table.index thead th[scope="row"] { - text-align: right; - } - - table.data tbody th:first-child, - table.index tbody th:first-child { - text-align: right; - } - -Possible extra rowspan handling - - table.data tbody th[rowspan]:not([rowspan='1']), - table.index tbody th[rowspan]:not([rowspan='1']), - table.data tbody td[rowspan]:not([rowspan='1']), - table.index tbody td[rowspan]:not([rowspan='1']) { - border-left: 1px solid silver; - } - - table.data tbody th[rowspan]:first-child, - table.index tbody th[rowspan]:first-child, - table.data tbody td[rowspan]:first-child, - table.index tbody td[rowspan]:first-child{ - border-left: 0; - border-right: 1px solid silver; - } -*/ - -/******************************************************************************/ -/* Indices */ -/******************************************************************************/ - - -/** Table of Contents *********************************************************/ - - .toc a { - /* More spacing; use padding to make it part of the click target. */ - padding: 0.1rem 1px 0; - /* Larger, more consistently-sized click target */ - display: block; - /* Switch to using border-bottom for underlines */ - text-decoration: none; - border-bottom: 1px solid; - /* Reverse color scheme */ - color: black; - color: var(--toclink-text); - border-color: #3980b5; - border-color: var(--toclink-underline); - } - .toc a:visited { - color: black; - color: var(--toclink-visited-text); - border-color: #054572; - border-color: var(--toclink-visited-underline); - } - .toc a:focus, - .toc a:hover { - background: rgba(75%, 75%, 75%, .25); - background: var(--a-hover-bg); - border-bottom-width: 3px; - margin-bottom: -2px; - } - .toc a:not(:focus):not(:hover) { - /* Allow colors to cascade through from link styling */ - border-bottom-color: transparent; - } - - .toc, .toc ol, .toc ul, .toc li { - list-style: none; /* Numbers must be inlined into source */ - /* because generated content isn't search/selectable and markers can't do multilevel yet */ - margin: 0; - padding: 0; - } - .toc { - line-height: 1.1em; - } - - /* ToC not indented until third level, but font style & margins show hierarchy */ - .toc > li { font-weight: bold; } - .toc > li li { font-weight: normal; } - .toc > li li li { font-size: 95%; } - .toc > li li li li { font-size: 90%; } - .toc > li li li li li { font-size: 85%; } - - /* @supports not (display:grid) { */ - .toc > li { margin: 1.5rem 0; } - .toc > li li { margin: 0.3rem 0; } - .toc > li li li { margin-left: 2rem; } - - /* Section numbers in a column of their own */ - .toc .secno { - float: left; - width: 4rem; - white-space: nowrap; - } - .toc > li li li li .secno { font-size: 85%; } - .toc > li li li li li .secno { font-size: 100%; } - - .toc li { - clear: both; - } - - :not(li) > .toc { margin-left: 5rem; } - .toc .secno { margin-left: -5rem; } - .toc > li li li .secno { margin-left: -7rem; } - .toc > li li li li .secno { margin-left: -9rem; } - .toc > li li li li li .secno { margin-left: -11rem; } - - /* Tighten up indentation in narrow ToCs */ - @media (max-width: 30em) { - :not(li) > .toc { margin-left: 4rem; } - .toc .secno { margin-left: -4rem; } - .toc > li li li { margin-left: 1rem; } - .toc > li li li .secno { margin-left: -5rem; } - .toc > li li li li .secno { margin-left: -6rem; } - .toc > li li li li li .secno { margin-left: -7rem; } - } - /* Loosen it on wide screens */ - @media screen and (min-width: 78em) { - body:not(.toc-inline) :not(li) > .toc { margin-left: 4rem; } - body:not(.toc-inline) .toc .secno { margin-left: -4rem; } - body:not(.toc-inline) .toc > li li li { margin-left: 1rem; } - body:not(.toc-inline) .toc > li li li .secno { margin-left: -5rem; } - body:not(.toc-inline) .toc > li li li li .secno { margin-left: -6rem; } - body:not(.toc-inline) .toc > li li li li li .secno { margin-left: -7rem; } - } - /* } */ - - @supports (display:grid) and (display:contents) { - /* Use #toc over .toc to override non-@supports rules. */ - #toc { - display: grid; - align-content: start; - grid-template-columns: auto 1fr; - grid-column-gap: 1rem; - column-gap: 1rem; - grid-row-gap: .6rem; - row-gap: .6rem; - } - #toc h2 { - grid-column: 1 / -1; - margin-bottom: 0; - } - #toc ol, - #toc li, - #toc a { - display: contents; - /* Switch <a> to subgrid when supported */ - } - #toc span { - margin: 0; - } - #toc > .toc > li > a > span { - /* The spans of the top-level list, - comprising the first items of each top-level section. */ - margin-top: 1.1rem; - } - #toc#toc .secno { /* Ugh, need more specificity to override base.css */ - grid-column: 1; - width: auto; - margin-left: 0; - } - #toc .content { - grid-column: 2; - width: auto; - margin-right: 1rem; - } - #toc .content:hover, - #toc .content:focus { - background: rgba(75%, 75%, 75%, .25); - background: var(--a-hover-bg); - border-bottom: 3px solid #054572; - border-bottom: 3px solid var(--toclink-underline); - margin-bottom: -3px; - } - #toc li li li .content { - margin-left: 1rem; - } - #toc li li li li .content { - margin-left: 2rem; - } - } - - -/** Index *********************************************************************/ - - /* Index Lists: Layout */ - ul.index { margin-left: 0; columns: 15em; text-indent: 1em hanging; } - ul.index li { margin-left: 0; list-style: none; break-inside: avoid; } - ul.index li li { margin-left: 1em; } - ul.index dl { margin-top: 0; } - ul.index dt { margin: .2em 0 .2em 20px;} - ul.index dd { margin: .2em 0 .2em 40px;} - /* Index Lists: Typography */ - ul.index ul, - ul.index dl { font-size: smaller; } - @media not print { - ul.index li a + span { - white-space: nowrap; - color: transparent; } - ul.index li a:hover + span, - ul.index li a:focus + span { - color: #707070; - color: var(--indexinfo-text); - } - } - -/** Index Tables *****************************************************/ - /* See also the data table styling section, which this effectively subclasses */ - - table.index { - font-size: small; - border-collapse: collapse; - border-spacing: 0; - text-align: left; - margin: 1em 0; - } - - table.index td, - table.index th { - padding: 0.4em; - } - - table.index tr:hover td:not([rowspan]), - table.index tr:hover th:not([rowspan]) { - color: black; - color: var(--indextable-hover-text); - background: #f7f8f9; - background: var(--indextable-hover-bg); - } - - /* The link in the first column in the property table (formerly a TD) */ - table.index th:first-child a { - font-weight: bold; - } - -/** Outdated warning **********************************************************/ - -.outdated-spec { - color: black; - color: var(--outdatedspec-text); - background-color: rgba(0,0,0,0.5); - background-color: var(--outdatedspec-bg); -} - -.outdated-warning { - position: fixed; - bottom: 50%; - left: 0; - right: 0; - margin: 0 auto; - width: 50%; - background: maroon; - background: var(--outdated-bg); - color: white; - color: var(--outdated-text); - border-radius: 1em; - box-shadow: 0 0 1em red; - box-shadow: 0 0 1em var(--outdated-shadow); - padding: 2em; - text-align: center; - z-index: 2; -} - -.outdated-warning a { - color: currentcolor; - background: transparent; -} - -.edited-rec-warning { - background: darkorange; - background: var(--editedrec-bg); - box-shadow: 0 0 1em; -} - -.outdated-warning button { - color: var(--outdated-text); - border-radius: 1em; - box-shadow: 0 0 1em red; - box-shadow: 0 0 1em var(--outdated-shadow); - padding: 2em; - text-align: center; - z-index: 2; -} - -.outdated-warning a { - color: currentcolor; - background: transparent; -} - -.edited-rec-warning { - background: darkorange; - background: var(--editedrec-bg); - box-shadow: 0 0 1em; -} - -.outdated-warning button { - position: absolute; - top: 0; - right:0; - margin: 0; - border: 0; - padding: 0.25em 0.5em; - background: transparent; - color: white; - color: var(--outdated-text); - font:1em sans-serif; - text-align:center; -} - -.outdated-warning span { - display: block; -} - -.outdated-collapsed { - bottom: 0; - border-radius: 0; - width: 100%; - padding: 0; -} - -/******************************************************************************/ -/* Print */ -/******************************************************************************/ - - @media print { - /* Pages have their own margins. */ - html { - margin: 0; - } - /* Serif for print. */ - body { - font-family: serif; - } - - .outdated-warning { - position: absolute; - border-style: solid; - border-color: red; - } - - .outdated-warning input { - display: none; - } - } - @page { - margin: 1.5cm 1.1cm; - } - - - -/******************************************************************************/ -/* Overflow Control */ -/******************************************************************************/ - - .figure .caption, .sidefigure .caption, figcaption { - /* in case figure is overlarge, limit caption to 50em */ - max-width: 50rem; - margin-left: auto; - margin-right: auto; - } - .overlarge { - /* Magic to create good item positioning: - "content column" is 50ems wide at max; less on smaller screens. - Extra space (after ToC + content) is empty on the right. - - 1. When item < content column, centers item in column. - 2. When content < item < available, left-aligns. - 3. When item > available, fills available + scroll bar. - */ - display: grid; - grid-template-columns: minmax(0, 50em); - } - .overlarge > table { - /* limit preferred width of table */ - max-width: 50em; - margin-left: auto; - margin-right: auto; - } - - @media (min-width: 55em) { - .overlarge { - margin-right: calc(13px + 26.5rem - 50vw); - max-width: none; - } - } - @media screen and (min-width: 78em) { - body:not(.toc-inline) .overlarge { - /* 30.5em body padding 50em content area */ - margin-right: calc(40em - 50vw) !important; - } - } - @media screen and (min-width: 90em) { - body:not(.toc-inline) .overlarge { - /* 4em html margin 30.5em body padding 50em content area */ - margin-right: calc(84.5em - 100vw) !important; - } - } - - @media not print { - .overlarge { - overflow-x: auto; - /* See Lea Verou's explanation background-attachment: - * http://lea.verou.me/2012/04/background-attachment-local/ - * - background: top left / 4em 100% linear-gradient(to right, #ffffff, rgba(255, 255, 255, 0)) local, - top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local, - top left / 1em 100% linear-gradient(to right, #c3c3c5, rgba(195, 195, 197, 0)) scroll, - top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll, - white; - background-repeat: no-repeat; - */ - } - } -</style> - <meta content="Bikeshed version 5fcd28d6d, updated Tue May 30 13:12:11 2023 -0700" name="generator"> - <meta content="2ec2dd7752939adf032c92c0ed97d7908b381965" name="document-revision"> -<style>/* Boilerplate: style-autolinks */ -.css.css, .property.property, .descriptor.descriptor { - color: var(--a-normal-text); - font-size: inherit; - font-family: inherit; -} -.css::before, .property::before, .descriptor::before { - content: "‘"; -} -.css::after, .property::after, .descriptor::after { - content: "’"; -} -.property, .descriptor { - /* Don't wrap property and descriptor names */ - white-space: nowrap; -} -.type { /* CSS value <type> */ - font-style: italic; -} -pre .property::before, pre .property::after { - content: ""; -} -[data-link-type="property"]::before, -[data-link-type="propdesc"]::before, -[data-link-type="descriptor"]::before, -[data-link-type="value"]::before, -[data-link-type="function"]::before, -[data-link-type="at-rule"]::before, -[data-link-type="selector"]::before, -[data-link-type="maybe"]::before { - content: "‘"; -} -[data-link-type="property"]::after, -[data-link-type="propdesc"]::after, -[data-link-type="descriptor"]::after, -[data-link-type="value"]::after, -[data-link-type="function"]::after, -[data-link-type="at-rule"]::after, -[data-link-type="selector"]::after, -[data-link-type="maybe"]::after { - content: "’"; -} - -[data-link-type].production::before, -[data-link-type].production::after, -.prod [data-link-type]::before, -.prod [data-link-type]::after { - content: ""; -} - -[data-link-type=element], -[data-link-type=element-attr] { - font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace; - font-size: .9em; -} -[data-link-type=element]::before { content: "<" } -[data-link-type=element]::after { content: ">" } - -[data-link-type=biblio] { - white-space: pre; -} - -@media (prefers-color-scheme: dark) { - :root { - --selflink-text: black; - --selflink-bg: silver; - --selflink-hover-text: white; - } -} -</style> -<style>/* Boilerplate: style-colors */ - -/* Any --*-text not paired with a --*-bg is assumed to have a transparent bg */ -:root { - color-scheme: light dark; - - --text: black; - --bg: white; - - --unofficial-watermark: url(https://www.w3.org/StyleSheets/TR/2016/logos/UD-watermark); - - --logo-bg: #1a5e9a; - --logo-active-bg: #c00; - --logo-text: white; - - --tocnav-normal-text: #707070; - --tocnav-normal-bg: var(--bg); - --tocnav-hover-text: var(--tocnav-normal-text); - --tocnav-hover-bg: #f8f8f8; - --tocnav-active-text: #c00; - --tocnav-active-bg: var(--tocnav-normal-bg); - - --tocsidebar-text: var(--text); - --tocsidebar-bg: #f7f8f9; - --tocsidebar-shadow: rgba(0,0,0,.1); - --tocsidebar-heading-text: hsla(203,20%,40%,.7); - - --toclink-text: var(--text); - --toclink-underline: #3980b5; - --toclink-visited-text: var(--toclink-text); - --toclink-visited-underline: #054572; - - --heading-text: #005a9c; - - --hr-text: var(--text); - - --algo-border: #def; - - --del-text: red; - --del-bg: transparent; - --ins-text: #080; - --ins-bg: transparent; - - --a-normal-text: #034575; - --a-normal-underline: #bbb; - --a-visited-text: var(--a-normal-text); - --a-visited-underline: #707070; - --a-hover-bg: rgba(75%, 75%, 75%, .25); - --a-active-text: #c00; - --a-active-underline: #c00; - - --blockquote-border: silver; - --blockquote-bg: transparent; - --blockquote-text: currentcolor; - - --issue-border: #e05252; - --issue-bg: #fbe9e9; - --issue-text: var(--text); - --issueheading-text: #831616; - - --example-border: #e0cb52; - --example-bg: #fcfaee; - --example-text: var(--text); - --exampleheading-text: #574b0f; - - --note-border: #52e052; - --note-bg: #e9fbe9; - --note-text: var(--text); - --noteheading-text: hsl(120, 70%, 30%); - --notesummary-underline: silver; - - --assertion-border: #aaa; - --assertion-bg: #eee; - --assertion-text: black; - - --advisement-border: orange; - --advisement-bg: #fec; - --advisement-text: var(--text); - --advisementheading-text: #b35f00; - - --warning-border: red; - --warning-bg: hsla(40,100%,50%,0.95); - --warning-text: var(--text); - - --amendment-border: #330099; - --amendment-bg: #F5F0FF; - --amendment-text: var(--text); - --amendmentheading-text: #220066; - - --def-border: #8ccbf2; - --def-bg: #def; - --def-text: var(--text); - --defrow-border: #bbd7e9; - - --datacell-border: silver; - - --indexinfo-text: #707070; - - --indextable-hover-text: black; - --indextable-hover-bg: #f7f8f9; - - --outdatedspec-bg: rgba(0, 0, 0, .5); - --outdatedspec-text: black; - --outdated-bg: maroon; - --outdated-text: white; - --outdated-shadow: red; - - --editedrec-bg: darkorange; -} - -@media (prefers-color-scheme: dark) { - :root { - --text: #ddd; - --bg: black; - - --unofficial-watermark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cg fill='%23100808' transform='translate(200 200) rotate(-45) translate(-200 -200)' stroke='%23100808' stroke-width='3'%3E%3Ctext x='50%25' y='220' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EUNOFFICIAL%3C/text%3E%3Ctext x='50%25' y='305' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EDRAFT%3C/text%3E%3C/g%3E%3C/svg%3E"); - - --logo-bg: #1a5e9a; - --logo-active-bg: #c00; - --logo-text: white; - - --tocnav-normal-text: #999; - --tocnav-normal-bg: var(--bg); - --tocnav-hover-text: var(--tocnav-normal-text); - --tocnav-hover-bg: #080808; - --tocnav-active-text: #f44; - --tocnav-active-bg: var(--tocnav-normal-bg); - - --tocsidebar-text: var(--text); - --tocsidebar-bg: #080808; - --tocsidebar-shadow: rgba(255,255,255,.1); - --tocsidebar-heading-text: hsla(203,20%,40%,.7); - - --toclink-text: var(--text); - --toclink-underline: #6af; - --toclink-visited-text: var(--toclink-text); - --toclink-visited-underline: #054572; - - --heading-text: #8af; - - --hr-text: var(--text); - - --algo-border: #456; - - --del-text: #f44; - --del-bg: transparent; - --ins-text: #4a4; - --ins-bg: transparent; - - --a-normal-text: #6af; - --a-normal-underline: #555; - --a-visited-text: var(--a-normal-text); - --a-visited-underline: var(--a-normal-underline); - --a-hover-bg: rgba(25%, 25%, 25%, .2); - --a-active-text: #f44; - --a-active-underline: var(--a-active-text); - - --borderedblock-bg: rgba(255, 255, 255, .05); - - --blockquote-border: silver; - --blockquote-bg: var(--borderedblock-bg); - --blockquote-text: currentcolor; - - --issue-border: #e05252; - --issue-bg: var(--borderedblock-bg); - --issue-text: var(--text); - --issueheading-text: hsl(0deg, 70%, 70%); - - --example-border: hsl(50deg, 90%, 60%); - --example-bg: var(--borderedblock-bg); - --example-text: var(--text); - --exampleheading-text: hsl(50deg, 70%, 70%); - - --note-border: hsl(120deg, 100%, 35%); - --note-bg: var(--borderedblock-bg); - --note-text: var(--text); - --noteheading-text: hsl(120, 70%, 70%); - --notesummary-underline: silver; - - --assertion-border: #444; - --assertion-bg: var(--borderedblock-bg); - --assertion-text: var(--text); - - --advisement-border: orange; - --advisement-bg: #222218; - --advisement-text: var(--text); - --advisementheading-text: #f84; - - --warning-border: red; - --warning-bg: hsla(40,100%,20%,0.95); - --warning-text: var(--text); - - --amendment-border: #330099; - --amendment-bg: #080010; - --amendment-text: var(--text); - --amendmentheading-text: #cc00ff; - - --def-border: #8ccbf2; - --def-bg: #080818; - --def-text: var(--text); - --defrow-border: #136; - - --datacell-border: silver; - - --indexinfo-text: #aaa; - - --indextable-hover-text: var(--text); - --indextable-hover-bg: #181818; - - --outdatedspec-bg: rgba(255, 255, 255, .5); - --outdatedspec-text: black; - --outdated-bg: maroon; - --outdated-text: white; - --outdated-shadow: red; - - --editedrec-bg: darkorange; - } - /* In case a transparent-bg image doesn't expect to be on a dark bg, - which is quite common in practice... */ - img { background: white; } -} -</style> -<style>/* Boilerplate: style-counters */ -body { - counter-reset: example figure issue; -} -.issue { - counter-increment: issue; -} -.issue:not(.no-marker)::before { - content: "Issue " counter(issue); -} - -.example { - counter-increment: example; -} -.example:not(.no-marker)::before { - content: "Example " counter(example); -} -.invalid.example:not(.no-marker)::before, -.illegal.example:not(.no-marker)::before { - content: "Invalid Example" counter(example); -} - -figcaption { - counter-increment: figure; -} -figcaption:not(.no-marker)::before { - content: "Figure " counter(figure) " "; -} -</style> -<style>/* Boilerplate: style-dfn-panel */ -:root { - --dfnpanel-bg: #ddd; - --dfnpanel-text: var(--text); -} -@media (prefers-color-scheme: dark) { - :root { - --dfnpanel-bg: #222; - --dfnpanel-text: var(--text); - } -} -.dfn-panel { - position: absolute; - z-index: 35; - width: 20em; - width: 300px; - height: auto; - max-height: 500px; - overflow: auto; - padding: 0.5em 0.75em; - font: small Helvetica Neue, sans-serif, Droid Sans Fallback; - background: var(--dfnpanel-bg); - color: var(--dfnpanel-text); - border: outset 0.2em; - white-space: normal; /* in case it's moved into a pre */ -} -.dfn-panel:not(.on) { display: none; } -.dfn-panel * { margin: 0; padding: 0; text-indent: 0; } -.dfn-panel > b { display: block; } -.dfn-panel a { color: var(--dfnpanel-text); } -.dfn-panel a:not(:hover) { text-decoration: none !important; border-bottom: none !important; } -.dfn-panel > b + b { margin-top: 0.25em; } -.dfn-panel ul { padding: 0 0 0 1em; list-style: none; } -.dfn-panel li a { - white-space: pre; - display: inline-block; - max-width: calc(300px - 1.5em - 1em); - overflow: hidden; - text-overflow: ellipsis; -} - -.dfn-panel.activated { - display: inline-block; - position: fixed; - left: .5em; - bottom: 2em; - margin: 0 auto; - max-width: calc(100vw - 1.5em - .4em - .5em); - max-height: 30vh; -} - -.dfn-paneled[role="button"] { cursor: pointer; } -</style> -<style>/* Boilerplate: style-dfn-panel */ -:root { - --dfnpanel-bg: #ddd; - --dfnpanel-text: var(--text); -} -@media (prefers-color-scheme: dark) { - :root { - --dfnpanel-bg: #222; - --dfnpanel-text: var(--text); - } -} -.dfn-panel { - position: absolute; - z-index: 35; - width: 20em; - width: 300px; - height: auto; - max-height: 500px; - overflow: auto; - padding: 0.5em 0.75em; - font: small Helvetica Neue, sans-serif, Droid Sans Fallback; - background: var(--dfnpanel-bg); - color: var(--dfnpanel-text); - border: outset 0.2em; - white-space: normal; /* in case it's moved into a pre */ -} -.dfn-panel:not(.on) { display: none; } -.dfn-panel * { margin: 0; padding: 0; text-indent: 0; } -.dfn-panel > b { display: block; } -.dfn-panel a { color: var(--dfnpanel-text); } -.dfn-panel a:not(:hover) { text-decoration: none !important; border-bottom: none !important; } -.dfn-panel > b + b { margin-top: 0.25em; } -.dfn-panel ul { padding: 0 0 0 1em; list-style: none; } -.dfn-panel li a { - white-space: pre; - display: inline-block; - max-width: calc(300px - 1.5em - 1em); - overflow: hidden; - text-overflow: ellipsis; -} - -.dfn-panel.activated { - display: inline-block; - position: fixed; - left: .5em; - bottom: 2em; - margin: 0 auto; - max-width: calc(100vw - 1.5em - .4em - .5em); - max-height: 30vh; -} - -.dfn-paneled[role="button"] { cursor: pointer; } -</style> -<style>/* Boilerplate: style-issues */ -a[href].issue-return { - float: right; - float: inline-end; - color: var(--issueheading-text); - font-weight: bold; - text-decoration: none; -} -</style> -<style>/* Boilerplate: style-md-lists */ -/* This is a weird hack for me not yet following the commonmark spec - regarding paragraph and lists. */ -[data-md] > :first-child { - margin-top: 0; -} -[data-md] > :last-child { - margin-bottom: 0; -} -</style> -<style>/* Boilerplate: style-selflinks */ - -:root { - --selflink-text: white; - --selflink-bg: gray; - --selflink-hover-text: black; -} -.heading, .issue, .note, .example, li, dt { - position: relative; -} -a.self-link { - position: absolute; - top: 0; - left: calc(-1 * (3.5rem - 26px)); - width: calc(3.5rem - 26px); - height: 2em; - text-align: center; - border: none; - transition: opacity .2s; - opacity: .5; -} -a.self-link:hover { - opacity: 1; -} -.heading > a.self-link { - font-size: 83%; -} -.example > a.self-link, -.note > a.self-link, -.issue > a.self-link { - /* These blocks are overflow:auto, so positioning outside - doesn't work. */ - left: auto; - right: 0; -} -li > a.self-link { - left: calc(-1 * (3.5rem - 26px) - 2em); -} -dfn > a.self-link { - top: auto; - left: auto; - opacity: 0; - width: 1.5em; - height: 1.5em; - background: var(--selflink-bg); - color: var(--selflink-text); - font-style: normal; - transition: opacity .2s, background-color .2s, color .2s; -} -dfn:hover > a.self-link { - opacity: 1; -} -dfn > a.self-link:hover { - color: var(--selflink-hover-text); -} - -a.self-link::before { content: "¶"; } -.heading > a.self-link::before { content: "§"; } -dfn > a.self-link::before { content: "#"; } -</style> -<style>/* Boilerplate: style-style-syntax-highlighting */ - - pre.idl.highlight { - background: var(--borderedblock-bg, var(--def-bg)); - } - -</style> -<style>/* Boilerplate: style-style-var-click-highlighting */ -/* -Colors were chosen in Lab using https://nixsensor.com/free-color-converter/ -D50 2deg illuminant, L in [0,100], a and b in [-128, 128] -0 = lab(85,0,85) -1 = lab(85,80,30) -2 = lab(85,-40,40) -3 = lab(85,-50,0) -4 = lab(85,5,15) -5 = lab(85,-10,-50) -6 = lab(85,35,-15) -*/ -var { cursor: pointer; } -var.selected0 { background-color: #F4D200; box-shadow: 0 0 0 2px #F4D200; } -var.selected1 { background-color: #FF87A2; box-shadow: 0 0 0 2px #FF87A2; } -var.selected2 { background-color: #96E885; box-shadow: 0 0 0 2px #96E885; } -var.selected3 { background-color: #3EEED2; box-shadow: 0 0 0 2px #3EEED2; } -var.selected4 { background-color: #EACFB6; box-shadow: 0 0 0 2px #EACFB6; } -var.selected5 { background-color: #82DDFF; box-shadow: 0 0 0 2px #82DDFF; } -var.selected6 { background-color: #FFBCF2; box-shadow: 0 0 0 2px #FFBCF2; } -</style> -<style>/* Boilerplate: style-syntax-highlighting */ - -code.highlight { padding: .1em; border-radius: .3em; } -pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; } - -.highlight:not(.idl) { background: rgba(0, 0, 0, .03); } -c-[a] { color: #990055 } /* Keyword.Declaration */ -c-[b] { color: #990055 } /* Keyword.Type */ -c-[c] { color: #708090 } /* Comment */ -c-[d] { color: #708090 } /* Comment.Multiline */ -c-[e] { color: #0077aa } /* Name.Attribute */ -c-[f] { color: #669900 } /* Name.Tag */ -c-[g] { color: #222222 } /* Name.Variable */ -c-[k] { color: #990055 } /* Keyword */ -c-[l] { color: #000000 } /* Literal */ -c-[m] { color: #000000 } /* Literal.Number */ -c-[n] { color: #0077aa } /* Name */ -c-[o] { color: #999999 } /* Operator */ -c-[p] { color: #999999 } /* Punctuation */ -c-[s] { color: #a67f59 } /* Literal.String */ -c-[t] { color: #a67f59 } /* Literal.String.Single */ -c-[u] { color: #a67f59 } /* Literal.String.Double */ -c-[cp] { color: #708090 } /* Comment.Preproc */ -c-[c1] { color: #708090 } /* Comment.Single */ -c-[cs] { color: #708090 } /* Comment.Special */ -c-[kc] { color: #990055 } /* Keyword.Constant */ -c-[kn] { color: #990055 } /* Keyword.Namespace */ -c-[kp] { color: #990055 } /* Keyword.Pseudo */ -c-[kr] { color: #990055 } /* Keyword.Reserved */ -c-[ld] { color: #000000 } /* Literal.Date */ -c-[nc] { color: #0077aa } /* Name.Class */ -c-[no] { color: #0077aa } /* Name.Constant */ -c-[nd] { color: #0077aa } /* Name.Decorator */ -c-[ni] { color: #0077aa } /* Name.Entity */ -c-[ne] { color: #0077aa } /* Name.Exception */ -c-[nf] { color: #0077aa } /* Name.Function */ -c-[nl] { color: #0077aa } /* Name.Label */ -c-[nn] { color: #0077aa } /* Name.Namespace */ -c-[py] { color: #0077aa } /* Name.Property */ -c-[ow] { color: #999999 } /* Operator.Word */ -c-[mb] { color: #000000 } /* Literal.Number.Bin */ -c-[mf] { color: #000000 } /* Literal.Number.Float */ -c-[mh] { color: #000000 } /* Literal.Number.Hex */ -c-[mi] { color: #000000 } /* Literal.Number.Integer */ -c-[mo] { color: #000000 } /* Literal.Number.Oct */ -c-[sb] { color: #a67f59 } /* Literal.String.Backtick */ -c-[sc] { color: #a67f59 } /* Literal.String.Char */ -c-[sd] { color: #a67f59 } /* Literal.String.Doc */ -c-[se] { color: #a67f59 } /* Literal.String.Escape */ -c-[sh] { color: #a67f59 } /* Literal.String.Heredoc */ -c-[si] { color: #a67f59 } /* Literal.String.Interpol */ -c-[sx] { color: #a67f59 } /* Literal.String.Other */ -c-[sr] { color: #a67f59 } /* Literal.String.Regex */ -c-[ss] { color: #a67f59 } /* Literal.String.Symbol */ -c-[vc] { color: #0077aa } /* Name.Variable.Class */ -c-[vg] { color: #0077aa } /* Name.Variable.Global */ -c-[vi] { color: #0077aa } /* Name.Variable.Instance */ -c-[il] { color: #000000 } /* Literal.Number.Integer.Long */ - - -@media (prefers-color-scheme: dark) { - .highlight:not(.idl) { background: rgba(255, 255, 255, .05); } - - c-[a] { color: #d33682 } /* Keyword.Declaration */ - c-[b] { color: #d33682 } /* Keyword.Type */ - c-[c] { color: #2aa198 } /* Comment */ - c-[d] { color: #2aa198 } /* Comment.Multiline */ - c-[e] { color: #268bd2 } /* Name.Attribute */ - c-[f] { color: #b58900 } /* Name.Tag */ - c-[g] { color: #cb4b16 } /* Name.Variable */ - c-[k] { color: #d33682 } /* Keyword */ - c-[l] { color: #657b83 } /* Literal */ - c-[m] { color: #657b83 } /* Literal.Number */ - c-[n] { color: #268bd2 } /* Name */ - c-[o] { color: #657b83 } /* Operator */ - c-[p] { color: #657b83 } /* Punctuation */ - c-[s] { color: #6c71c4 } /* Literal.String */ - c-[t] { color: #6c71c4 } /* Literal.String.Single */ - c-[u] { color: #6c71c4 } /* Literal.String.Double */ - c-[ch] { color: #2aa198 } /* Comment.Hashbang */ - c-[cp] { color: #2aa198 } /* Comment.Preproc */ - c-[cpf] { color: #2aa198 } /* Comment.PreprocFile */ - c-[c1] { color: #2aa198 } /* Comment.Single */ - c-[cs] { color: #2aa198 } /* Comment.Special */ - c-[kc] { color: #d33682 } /* Keyword.Constant */ - c-[kn] { color: #d33682 } /* Keyword.Namespace */ - c-[kp] { color: #d33682 } /* Keyword.Pseudo */ - c-[kr] { color: #d33682 } /* Keyword.Reserved */ - c-[ld] { color: #657b83 } /* Literal.Date */ - c-[nc] { color: #268bd2 } /* Name.Class */ - c-[no] { color: #268bd2 } /* Name.Constant */ - c-[nd] { color: #268bd2 } /* Name.Decorator */ - c-[ni] { color: #268bd2 } /* Name.Entity */ - c-[ne] { color: #268bd2 } /* Name.Exception */ - c-[nf] { color: #268bd2 } /* Name.Function */ - c-[nl] { color: #268bd2 } /* Name.Label */ - c-[nn] { color: #268bd2 } /* Name.Namespace */ - c-[py] { color: #268bd2 } /* Name.Property */ - c-[ow] { color: #657b83 } /* Operator.Word */ - c-[mb] { color: #657b83 } /* Literal.Number.Bin */ - c-[mf] { color: #657b83 } /* Literal.Number.Float */ - c-[mh] { color: #657b83 } /* Literal.Number.Hex */ - c-[mi] { color: #657b83 } /* Literal.Number.Integer */ - c-[mo] { color: #657b83 } /* Literal.Number.Oct */ - c-[sa] { color: #6c71c4 } /* Literal.String.Affix */ - c-[sb] { color: #6c71c4 } /* Literal.String.Backtick */ - c-[sc] { color: #6c71c4 } /* Literal.String.Char */ - c-[dl] { color: #6c71c4 } /* Literal.String.Delimiter */ - c-[sd] { color: #6c71c4 } /* Literal.String.Doc */ - c-[se] { color: #6c71c4 } /* Literal.String.Escape */ - c-[sh] { color: #6c71c4 } /* Literal.String.Heredoc */ - c-[si] { color: #6c71c4 } /* Literal.String.Interpol */ - c-[sx] { color: #6c71c4 } /* Literal.String.Other */ - c-[sr] { color: #6c71c4 } /* Literal.String.Regex */ - c-[ss] { color: #6c71c4 } /* Literal.String.Symbol */ - c-[fm] { color: #268bd2 } /* Name.Function.Magic */ - c-[vc] { color: #cb4b16 } /* Name.Variable.Class */ - c-[vg] { color: #cb4b16 } /* Name.Variable.Global */ - c-[vi] { color: #cb4b16 } /* Name.Variable.Instance */ - c-[vm] { color: #cb4b16 } /* Name.Variable.Magic */ - c-[il] { color: #657b83 } /* Literal.Number.Integer.Long */ -} -</style> - <body class="h-entry"> - <div class="head"> - <p data-fill-with="logo"></p> - <h1 class="p-name no-ref" id="title">Web Environment Integrity</h1> - <h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">A Collection of Interesting Ideas, <time class="dt-updated" datetime="2023-06-16">16 June 2023</time></span></h2> - <div data-fill-with="spec-metadata"> - <dl> - <dt>Issue Tracking: - <dd><a href="https://github.com/RupertBenWiser/Web-Environment-Integrity/issues/">GitHub</a> - <dt class="editor">Editor: - <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:bewise@chromium.org">Ben Wiser</a> (<span class="p-org org">Google</span>) - </dl> - </div> - <div data-fill-with="warning"></div> - <p class="copyright" data-fill-with="copyright"><a href="http://creativecommons.org/publicdomain/zero/1.0/" rel="license"><img alt="CC0" height="15" src="https://licensebuttons.net/p/zero/1.0/80x15.png" width="80"></a> To the extent possible under law, the editors have waived all copyright -and related or neighboring rights to this work. -In addition, as of 16 June 2023, -the editors have made this specification available under the <a href="http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0" rel="license">Open Web Foundation Agreement Version 1.0</a>, -which is available at http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0. -Parts of this work may be from another specification document. If so, those parts are instead covered by the license of that specification document. </p> - <hr title="Separator for header"> - </div> - <div class="p-summary" data-fill-with="abstract"> - <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2> - <p>An API used to integrity check the environment a web page runs on. This check is performed - -by trusted attesters.</p> - </div> - <div data-fill-with="at-risk"></div> - <nav data-fill-with="table-of-contents" id="toc"> - <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2> - <ol class="toc" role="directory"> - <li> - <a href="#introduction"><span class="secno">1</span> <span class="content">Introduction</span></a> - <ol class="toc"> - <li><a href="#motivations"><span class="secno">1.1</span> <span class="content">Motivations</span></a> - <li><a href="#examples"><span class="secno">1.2</span> <span class="content">Examples</span></a> - </ol> - <li><a href="#key-terms"><span class="secno">2</span> <span class="content">Key terms</span></a> - <li> - <a href="#attester"><span class="secno">3</span> <span class="content">Attesters</span></a> - <ol class="toc"> - <li><a href="#attester-tokens"><span class="secno">3.1</span> <span class="content">Token Format</span></a> - <li><a href="#attester-browser-requirements"><span class="secno">3.2</span> <span class="content">Browser Acceptance Requirements</span></a> - <li><a href="#attester-connection"><span class="secno">3.3</span> <span class="content"><code class="idl"><span>AttesterConnection</span></code></span></a> - </ol> - <li> - <a href="#api"><span class="secno">4</span> <span class="content">Web Environment Integrity API</span></a> - <ol class="toc"> - <li> - <a href="#extensions-to-navigator"><span class="secno">4.1</span> <span class="content">Extensions to <code class="idl"><span>Navigator</span></code></span></a> - <ol class="toc"> - <li><a href="#navigator-getenvironmentintegrity"><span class="secno">4.1.1</span> <span class="content"><code class="idl"><span>getEnvironmentIntegrity()</span></code></span></a> - </ol> - <li><a href="#environment-integrity"><span class="secno">4.2</span> <span class="content"><code class="idl"><span>EnvironmentIntegrity</span></code></span></a> - </ol> - <li> - <a href="#security-and-privacy"><span class="secno">5</span> <span class="content">Security and privacy considerations</span></a> - <ol class="toc"> - <li><a href="#security"><span class="secno">5.1</span> <span class="content">Security considerations</span></a> - <li><a href="#privacy"><span class="secno">5.2</span> <span class="content">Privacy considerations</span></a> - </ol> - <li><a href="#conformance"><span class="secno"></span> <span class="content"> Conformance</span></a> - <li> - <a href="#index"><span class="secno"></span> <span class="content">Index</span></a> - <ol class="toc"> - <li><a href="#index-defined-here"><span class="secno"></span> <span class="content">Terms defined by this specification</span></a> - <li><a href="#index-defined-elsewhere"><span class="secno"></span> <span class="content">Terms defined by reference</span></a> - </ol> - <li> - <a href="#references"><span class="secno"></span> <span class="content">References</span></a> - <ol class="toc"> - <li><a href="#normative"><span class="secno"></span> <span class="content">Normative References</span></a> - </ol> - <li><a href="#idl-index"><span class="secno"></span> <span class="content">IDL Index</span></a> - </ol> - </nav> - <main> - <h2 class="heading settled" data-level="1" id="introduction"><span class="secno">1. </span><span class="content">Introduction</span><a class="self-link" href="#introduction"></a></h2> - <p><i>Todo</i></p> - <h3 class="heading settled" data-level="1.1" id="motivations"><span class="secno">1.1. </span><span class="content">Motivations</span><a class="self-link" href="#motivations"></a></h3> - <p><i>Todo</i></p> - <h3 class="heading settled" data-level="1.2" id="examples"><span class="secno">1.2. </span><span class="content">Examples</span><a class="self-link" href="#examples"></a></h3> - <div class="example" id="client-integrity-request"> - <a class="self-link" href="#client-integrity-request"></a> Requesting environment integrity attestation. -<pre class="lang-js highlight"><c- c1>// getEnvironmentIntegrity expects a "content binding" of the request you are</c-> -<c- c1>// about to make. The content binding protects against this information being</c-> -<c- c1>// used for a different request.</c-> -<c- c1>// The contentBinding will be concatenated with top-level domain name and hashed</c-> -<c- c1>// before it is sent to the attester.</c-> - -<c- a>const</c-> contentBinding <c- o>=</c-> <c- u>"/someRequestPath?requestID=xxxx"</c-> <c- o>+</c-> - <c- u>"Any other data needed for a request-specific contentBinding..."</c-><c- p>;</c-> - -<c- a>const</c-> attestation <c- o>=</c-> <c- k>await</c-> navigator<c- p>.</c->getEnvironmentIntegrity<c- p>(</c->contentBinding<c- p>);</c-> - -console<c- p>.</c->log<c- p>(</c->attestation<c- p>.</c->encode<c- p>());</c-> -<c- u>"base-64 encoding of the attestation payload and signature approx 500 bytes; see below for details"</c-> - -<c- c1>// More on attestation validation below</c-> -<c- a>const</c-> response <c- o>=</c-> <c- k>await</c-> fetch<c- p>(</c-><c- sb>`/someRequest?requestID=xxxx&amp;attested=</c-><c- si>${</c->attestation<c- p>.</c->encode<c- p>()</c-><c- si>}</c-><c- sb>`</c-><c- p>);</c-> -<c- c1>// Do something with this ...</c-> -</pre> - </div> - <h2 class="heading settled" data-level="2" id="key-terms"><span class="secno">2. </span><span class="content">Key terms</span><a class="self-link" href="#key-terms"></a></h2> - <p>The <dfn class="dfn-paneled" data-dfn-for="web environment" data-dfn-type="dfn" data-noexport id="web-environment-web-environment">web environment</dfn> is defined as <i>TODO</i></p> - <h2 class="heading settled" data-level="3" id="attester"><span class="secno">3. </span><span class="content">Attesters</span><a class="self-link" href="#attester"></a></h2> - <p>The term <dfn class="dfn-paneled" data-dfn-for="attester" data-dfn-type="dfn" data-noexport id="attester-attester">attester</dfn> refers to a third party capable of returning an <a data-link-type="dfn" href="#integrity-verdict-integrity-verdict" id="ref-for-integrity-verdict-integrity-verdict">Integrity verdict</a>. A <dfn class="dfn-paneled" data-dfn-for="Integrity verdict" data-dfn-type="dfn" data-noexport id="integrity-verdict-integrity-verdict">Integrity verdict</dfn> refers -to a response that confirms if the <a data-link-type="dfn" href="#attester-attester" id="ref-for-attester-attester">attester</a> trusts the <a data-link-type="dfn" href="#web-environment-web-environment" id="ref-for-web-environment-web-environment">web environment</a> the <a data-link-type="dfn" href="https://infra.spec.whatwg.org/#user-agent" id="ref-for-user-agent">user agent</a> is -executing in.</p> - <p>The <a data-link-type="dfn" href="https://infra.spec.whatwg.org/#user-agent" id="ref-for-user-agent①">user agent</a> connects to the <a data-link-type="dfn" href="#attester-attester" id="ref-for-attester-attester①">attester</a> through an <code class="idl"><a data-link-type="idl" href="#attesterconnection" id="ref-for-attesterconnection">AttesterConnection</a></code>.</p> - <p>The <a data-link-type="dfn" href="https://infra.spec.whatwg.org/#user-agent" id="ref-for-user-agent②">user agent</a> SHOULD use separate <code class="idl"><a data-link-type="idl" href="#attesterconnection" id="ref-for-attesterconnection①">AttesterConnection</a></code>s if the <code class="idl"><a data-link-type="idl" href="#attesterconnection" id="ref-for-attesterconnection②">AttesterConnection</a></code> stores state in the <a data-link-type="dfn" href="#integrity-verdict-integrity-verdict" id="ref-for-integrity-verdict-integrity-verdict①">Integrity verdict</a> that can be used for cross site tracking.</p> - <h3 class="heading settled" data-level="3.1" id="attester-tokens"><span class="secno">3.1. </span><span class="content">Token Format</span><a class="self-link" href="#attester-tokens"></a></h3> - <p><i>Todo</i></p> - <h3 class="heading settled" data-level="3.2" id="attester-browser-requirements"><span class="secno">3.2. </span><span class="content">Browser Acceptance Requirements</span><a class="self-link" href="#attester-browser-requirements"></a></h3> - <p><i>Todo</i></p> - <h3 class="heading settled" data-level="3.3" id="attester-connection"><span class="secno">3.3. </span><span class="content"><code class="idl"><a data-link-type="idl" href="#attesterconnection" id="ref-for-attesterconnection③">AttesterConnection</a></code></span><a class="self-link" href="#attester-connection"></a></h3> -<pre class="idl highlight def"><c- b>interface</c-> <dfn class="dfn-paneled idl-code" data-dfn-type="interface" data-export id="attesterconnection"><code><c- g>AttesterConnection</c-></code></dfn> { - <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-ArrayBuffer" id="ref-for-idl-ArrayBuffer"><c- b>ArrayBuffer</c-></a> <dfn class="dfn-paneled idl-code" data-dfn-for="AttesterConnection" data-dfn-type="method" data-export data-lt="getAttestation(contentBinding)" id="dom-attesterconnection-getattestation"><code><c- g>getAttestation</c-></code></dfn>(<a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-DOMString" id="ref-for-idl-DOMString"><c- b>DOMString</c-></a> <dfn class="idl-code" data-dfn-for="AttesterConnection/getAttestation(contentBinding)" data-dfn-type="argument" data-export id="dom-attesterconnection-getattestation-contentbinding-contentbinding"><code><c- g>contentBinding</c-></code><a class="self-link" href="#dom-attesterconnection-getattestation-contentbinding-contentbinding"></a></dfn>); -}; -</pre> - <dl> - <dt data-md>getAttestation - <dd data-md> - <p>Returns a COSE signed CBOR object as an ArrayBuffer from the <a data-link-type="dfn" href="#attester-attester" id="ref-for-attester-attester②">attester</a> that contains the <a data-link-type="dfn" href="#integrity-verdict-integrity-verdict" id="ref-for-integrity-verdict-integrity-verdict②">Integrity verdict</a>.</p> - </dl> - <h2 class="heading settled" data-level="4" id="api"><span class="secno">4. </span><span class="content">Web Environment Integrity API</span><a class="self-link" href="#api"></a></h2> - <h3 class="heading settled" data-level="4.1" id="extensions-to-navigator"><span class="secno">4.1. </span><span class="content">Extensions to <code class="idl"><a data-link-type="idl" href="https://html.spec.whatwg.org/multipage/system-state.html#navigator" id="ref-for-navigator">Navigator</a></code></span><a class="self-link" href="#extensions-to-navigator"></a></h3> -<pre class="idl highlight def">[<a class="idl-code" data-link-type="extended-attribute" href="https://webidl.spec.whatwg.org/#Exposed" id="ref-for-Exposed"><c- g>Exposed</c-></a>=<c- n>Window</c->] -<c- b>partial</c-> <c- b>interface</c-> <a class="idl-code" data-link-type="interface" href="https://html.spec.whatwg.org/multipage/system-state.html#navigator" id="ref-for-navigator①"><c- g>Navigator</c-></a> { - [<a class="idl-code" data-link-type="extended-attribute" href="https://webidl.spec.whatwg.org/#SecureContext" id="ref-for-SecureContext"><c- g>SecureContext</c-></a>] <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-promise" id="ref-for-idl-promise"><c- b>Promise</c-></a>&lt;<a data-link-type="idl-name" href="#environmentintegrity" id="ref-for-environmentintegrity"><c- n>EnvironmentIntegrity</c-></a>> <a class="idl-code" data-link-type="method" href="#dom-navigator-getenvironmentintegrity" id="ref-for-dom-navigator-getenvironmentintegrity"><c- g>getEnvironmentIntegrity</c-></a>(<a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-DOMString" id="ref-for-idl-DOMString①"><c- b>DOMString</c-></a> <dfn class="idl-code" data-dfn-for="Navigator/getEnvironmentIntegrity(contentBinding)" data-dfn-type="argument" data-export id="dom-navigator-getenvironmentintegrity-contentbinding-contentbinding"><code><c- g>contentBinding</c-></code><a class="self-link" href="#dom-navigator-getenvironmentintegrity-contentbinding-contentbinding"></a></dfn>); -}; -</pre> - <h4 class="heading settled" data-level="4.1.1" id="navigator-getenvironmentintegrity"><span class="secno">4.1.1. </span><span class="content"><code class="idl"><a data-link-type="idl" href="#dom-navigator-getenvironmentintegrity" id="ref-for-dom-navigator-getenvironmentintegrity①">getEnvironmentIntegrity()</a></code></span><a class="self-link" href="#navigator-getenvironmentintegrity"></a></h4> - <div class="algorithm" data-algorithm="navigator-getenvironmentintegrity-alg"> - The <a data-link-type="dfn" href="https://infra.spec.whatwg.org/#user-agent" id="ref-for-user-agent③">user agent</a> has the global <dfn class="dfn-paneled" data-dfn-for="attesterConnection" data-dfn-type="dfn" data-noexport id="attesterconnection-attesterconnection">attesterConnection</dfn>, which is - an <code class="idl"><a data-link-type="idl" href="#attesterconnection" id="ref-for-attesterconnection④">AttesterConnection</a></code> with the <a data-link-type="dfn" href="#attester-attester" id="ref-for-attester-attester③">attester</a>. - <p>The <dfn class="dfn-paneled idl-code" data-dfn-for="Navigator" data-dfn-type="method" data-export id="dom-navigator-getenvironmentintegrity"><code>getEnvironmentIntegrity(<var>contentBinding</var>)</code></dfn> method, when invoked, runs these steps:</p> - <ol> - <li data-md> - <p>Let <var>promise</var> be <a data-link-type="dfn" href="https://webidl.spec.whatwg.org/#a-new-promise" id="ref-for-a-new-promise">a new promise</a></p> - <li data-md> - <p>Run the following steps <a data-link-type="dfn" href="https://html.spec.whatwg.org/multipage/infrastructure.html#in-parallel" id="ref-for-in-parallel">in parallel</a>:</p> - <ol> - <li data-md> - <p>Let <var>environmentIntegrity</var> be a new <code class="idl"><a data-link-type="idl" href="#environmentintegrity" id="ref-for-environmentintegrity①">EnvironmentIntegrity</a></code></p> - <li data-md> - <p>Set <var>environmentIntegrity</var>.<code class="idl"><a data-link-type="idl" href="#dom-environmentintegrity-attestationtoken" id="ref-for-dom-environmentintegrity-attestationtoken">attestationToken</a></code> to <a data-link-type="dfn" href="#attesterconnection-attesterconnection" id="ref-for-attesterconnection-attesterconnection">attesterConnection</a>.<a class="idl-code" data-link-type="method" href="#dom-attesterconnection-getattestation" id="ref-for-dom-attesterconnection-getattestation">getAttestation(<var>contentBinding</var>)</a>. If this fails then:</p> - <ol> - <li data-md> - <p><a data-link-type="dfn" href="https://webidl.spec.whatwg.org/#reject" id="ref-for-reject">Reject</a> <var>promise</var> with a <i>TODO</i> <a data-link-type="dfn" href="https://webidl.spec.whatwg.org/#dfn-exception" id="ref-for-dfn-exception">Exception</a></p> - <li data-md> - <p>Abort these steps</p> - </ol> - <li data-md> - <p><a data-link-type="dfn" href="https://webidl.spec.whatwg.org/#resolve" id="ref-for-resolve">Resolve</a> <var>promise</var> with <var>environmentIntegrity</var></p> - </ol> - <li data-md> - <p>Return <var>promise</var></p> - </ol> - </div> - <h3 class="heading settled" data-level="4.2" id="environment-integrity"><span class="secno">4.2. </span><span class="content"><code class="idl"><a data-link-type="idl" href="#environmentintegrity" id="ref-for-environmentintegrity②">EnvironmentIntegrity</a></code></span><a class="self-link" href="#environment-integrity"></a></h3> -<pre class="idl highlight def"><c- b>interface</c-> <dfn class="dfn-paneled idl-code" data-dfn-type="interface" data-export id="environmentintegrity"><code><c- g>EnvironmentIntegrity</c-></code></dfn> { - <c- b>readonly</c-> <c- b>attribute</c-> <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-ArrayBuffer" id="ref-for-idl-ArrayBuffer①"><c- b>ArrayBuffer</c-></a> <dfn class="dfn-paneled idl-code" data-dfn-for="EnvironmentIntegrity" data-dfn-type="attribute" data-export data-readonly data-type="ArrayBuffer" id="dom-environmentintegrity-attestationtoken"><code><c- g>attestationToken</c-></code></dfn>; - <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-DOMString" id="ref-for-idl-DOMString②"><c- b>DOMString</c-></a> <dfn class="idl-code" data-dfn-for="EnvironmentIntegrity" data-dfn-type="method" data-export data-lt="encode()" id="dom-environmentintegrity-encode"><code><c- g>encode</c-></code><a class="self-link" href="#dom-environmentintegrity-encode"></a></dfn>(); - <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-object" id="ref-for-idl-object"><c- b>object</c-></a> <dfn class="idl-code" data-dfn-for="EnvironmentIntegrity" data-dfn-type="method" data-export data-lt="toJSON()" id="dom-environmentintegrity-tojson"><code><c- g>toJSON</c-></code><a class="self-link" href="#dom-environmentintegrity-tojson"></a></dfn>(); -}; -</pre> - <dl> - <dt data-md>attestationToken - <dd data-md> - <p>The attestation token is a COSE signed CBOR object as an ArrayBuffer from the attester.</p> - <dt data-md>encode() - <dd data-md> - <p>The encode method will return a Base64 string representation of the attestation token.</p> - <dt data-md>toJSON() - <dd data-md> - <p>The toJSON method returns a human readable JSON representation of the attestation token. It will first decode the CBOR object. Useful for local debugging.</p> - </dl> - <h2 class="heading settled" data-level="5" id="security-and-privacy"><span class="secno">5. </span><span class="content">Security and privacy considerations</span><a class="self-link" href="#security-and-privacy"></a></h2> - <h3 class="heading settled" data-level="5.1" id="security"><span class="secno">5.1. </span><span class="content">Security considerations</span><a class="self-link" href="#security"></a></h3> - <p><i>Todo</i></p> - <h3 class="heading settled" data-level="5.2" id="privacy"><span class="secno">5.2. </span><span class="content">Privacy considerations</span><a class="self-link" href="#privacy"></a></h3> - <p><i>Todo</i></p> - </main> - <div data-fill-with="conformance"> - <h2 class="no-ref no-num heading settled" id="conformance"><span class="content"> Conformance</span><a class="self-link" href="#conformance"></a></h2> - <p> Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. - The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” - in the normative parts of this document - are to be interpreted as described in RFC 2119. - However, for readability, - these words do not appear in all uppercase letters in this specification. </p> - <p> All of the text of this specification is normative - except sections explicitly marked as non-normative, examples, and notes. <a data-link-type="biblio" href="#biblio-rfc2119" title="Key words for use in RFCs to Indicate Requirement Levels">[RFC2119]</a> </p> - <p> Examples in this specification are introduced with the words “for example” - or are set apart from the normative text with <code>class="example"</code>, like this: </p> - <div class="example" id="example-example"><a class="self-link" href="#example-example"></a> This is an example of an informative example. </div> - <p> Informative notes begin with the word “Note” - and are set apart from the normative text with <code>class="note"</code>, like this: </p> - <p class="note" role="note"> Note, this is an informative note.</p> - </div> -<script> -(function() { - "use strict"; - var collapseSidebarText = '<span aria-hidden="true">←</span> ' - + '<span>Collapse Sidebar</span>'; - var expandSidebarText = '<span aria-hidden="true">→</span> ' - + '<span>Pop Out Sidebar</span>'; - var tocJumpText = '<span aria-hidden="true">↑</span> ' - + '<span>Jump to Table of Contents</span>'; - - var sidebarMedia = window.matchMedia('screen and (min-width: 78em)'); - var autoToggle = function(e){ toggleSidebar(e.matches) }; - if(sidebarMedia.addListener) { - sidebarMedia.addListener(autoToggle); - } - - function toggleSidebar(on) { - if (on == undefined) { - on = !document.body.classList.contains('toc-sidebar'); - } - - /* Don’t scroll to compensate for the ToC if we’re above it already. */ - var headY = 0; - var head = document.querySelector('.head'); - if (head) { - // terrible approx of "top of ToC" - headY += head.offsetTop + head.offsetHeight; - } - var skipScroll = window.scrollY < headY; - - var toggle = document.getElementById('toc-toggle'); - var tocNav = document.getElementById('toc'); - if (on) { - var tocHeight = tocNav.offsetHeight; - document.body.classList.add('toc-sidebar'); - document.body.classList.remove('toc-inline'); - toggle.innerHTML = collapseSidebarText; - if (!skipScroll) { - window.scrollBy(0, 0 - tocHeight); - } - tocNav.focus(); - sidebarMedia.addListener(autoToggle); // auto-collapse when out of room - } - else { - document.body.classList.add('toc-inline'); - document.body.classList.remove('toc-sidebar'); - toggle.innerHTML = expandSidebarText; - if (!skipScroll) { - window.scrollBy(0, tocNav.offsetHeight); - } - if (toggle.matches(':hover')) { - /* Unfocus button when not using keyboard navigation, - because I don’t know where else to send the focus. */ - toggle.blur(); - } - } - } - - function createSidebarToggle() { - /* Create the sidebar toggle in JS; it shouldn’t exist when JS is off. */ - var toggle = document.createElement('a'); - /* This should probably be a button, but appearance isn’t standards-track.*/ - toggle.id = 'toc-toggle'; - toggle.class = 'toc-toggle'; - toggle.href = '#toc'; - toggle.innerHTML = collapseSidebarText; - - sidebarMedia.addListener(autoToggle); - var toggler = function(e) { - e.preventDefault(); - sidebarMedia.removeListener(autoToggle); // persist explicit off states - toggleSidebar(); - return false; - } - toggle.addEventListener('click', toggler, false); - - - /* Get <nav id=toc-nav>, or make it if we don’t have one. */ - var tocNav = document.getElementById('toc-nav'); - if (!tocNav) { - tocNav = document.createElement('p'); - tocNav.id = 'toc-nav'; - /* Prepend for better keyboard navigation */ - document.body.insertBefore(tocNav, document.body.firstChild); - } - /* While we’re at it, make sure we have a Jump to Toc link. */ - var tocJump = document.getElementById('toc-jump'); - if (!tocJump) { - tocJump = document.createElement('a'); - tocJump.id = 'toc-jump'; - tocJump.href = '#toc'; - tocJump.innerHTML = tocJumpText; - tocNav.appendChild(tocJump); - } - - tocNav.appendChild(toggle); - } - - var toc = document.getElementById('toc'); - if (toc) { - createSidebarToggle(); - toggleSidebar(sidebarMedia.matches); - - /* If the sidebar has been manually opened and is currently overlaying the text - (window too small for the MQ to add the margin to body), - then auto-close the sidebar once you click on something in there. */ - toc.addEventListener('click', function(e) { - if(e.target.tagName.toLowerCase() == "a" && document.body.classList.contains('toc-sidebar') && !sidebarMedia.matches) { - toggleSidebar(false); - } - }, false); - } - else { - console.warn("Can’t find Table of Contents. Please use <nav id='toc'> around the ToC."); - } - - /* Wrap tables in case they overflow */ - var tables = document.querySelectorAll(':not(.overlarge) > table.data, :not(.overlarge) > table.index'); - var numTables = tables.length; - for (var i = 0; i < numTables; i++) { - var table = tables[i]; - var wrapper = document.createElement('div'); - wrapper.className = 'overlarge'; - table.parentNode.insertBefore(wrapper, table); - wrapper.appendChild(table); - } - -})(); -</script> - <h2 class="no-num no-ref heading settled" id="index"><span class="content">Index</span><a class="self-link" href="#index"></a></h2> - <h3 class="no-num no-ref heading settled" id="index-defined-here"><span class="content">Terms defined by this specification</span><a class="self-link" href="#index-defined-here"></a></h3> - <ul class="index"> - <li><a href="#dom-environmentintegrity-attestationtoken">attestationToken</a><span>, in § 4.2</span> - <li><a href="#attester-attester">attester</a><span>, in § 3</span> - <li><a href="#attesterconnection">AttesterConnection</a><span>, in § 3.3</span> - <li><a href="#attesterconnection-attesterconnection">attesterConnection</a><span>, in § 4.1.1</span> - <li><a href="#dom-environmentintegrity-encode">encode()</a><span>, in § 4.2</span> - <li><a href="#environmentintegrity">EnvironmentIntegrity</a><span>, in § 4.2</span> - <li><a href="#dom-attesterconnection-getattestation">getAttestation(contentBinding)</a><span>, in § 3.3</span> - <li><a href="#dom-navigator-getenvironmentintegrity">getEnvironmentIntegrity(contentBinding)</a><span>, in § 4.1.1</span> - <li><a href="#integrity-verdict-integrity-verdict">Integrity verdict</a><span>, in § 3</span> - <li><a href="#dom-environmentintegrity-tojson">toJSON()</a><span>, in § 4.2</span> - <li><a href="#web-environment-web-environment">web environment</a><span>, in § 2</span> - </ul> - <h3 class="no-num no-ref heading settled" id="index-defined-elsewhere"><span class="content">Terms defined by reference</span><a class="self-link" href="#index-defined-elsewhere"></a></h3> - <ul class="index"> - <li> - <a data-link-type="biblio">[HTML]</a> defines the following terms: - <ul> - <li><span class="dfn-paneled" id="be0c27b2">Navigator</span> - <li><span class="dfn-paneled" id="a72449dd">in parallel</span> - </ul> - <li> - <a data-link-type="biblio">[INFRA]</a> defines the following terms: - <ul> - <li><span class="dfn-paneled" id="6d19ac93">user agent</span> - </ul> - <li> - <a data-link-type="biblio">[WEBIDL]</a> defines the following terms: - <ul> - <li><span class="dfn-paneled" id="2f8afbfe">ArrayBuffer</span> - <li><span class="dfn-paneled" id="8855a9aa">DOMString</span> - <li><span class="dfn-paneled" id="889e932f">Exposed</span> - <li><span class="dfn-paneled" id="bdbd19d1">Promise</span> - <li><span class="dfn-paneled" id="b75bb3bd">SecureContext</span> - <li><span class="dfn-paneled" id="dacde8b5">a new promise</span> - <li><span class="dfn-paneled" id="cd787c3f">exception</span> - <li><span class="dfn-paneled" id="efd1ec5d">object</span> - <li><span class="dfn-paneled" id="b262501e">reject</span> - <li><span class="dfn-paneled" id="3b90bdcd">resolve</span> - </ul> - </ul> - <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2> - <h3 class="no-num no-ref heading settled" id="normative"><span class="content">Normative References</span><a class="self-link" href="#normative"></a></h3> - <dl> - <dt id="biblio-html">[HTML] - <dd>Anne van Kesteren; et al. <a href="https://html.spec.whatwg.org/multipage/"><cite>HTML Standard</cite></a>. Living Standard. URL: <a href="https://html.spec.whatwg.org/multipage/">https://html.spec.whatwg.org/multipage/</a> - <dt id="biblio-infra">[INFRA] - <dd>Anne van Kesteren; Domenic Denicola. <a href="https://infra.spec.whatwg.org/"><cite>Infra Standard</cite></a>. Living Standard. URL: <a href="https://infra.spec.whatwg.org/">https://infra.spec.whatwg.org/</a> - <dt id="biblio-rfc2119">[RFC2119] - <dd>S. Bradner. <a href="https://datatracker.ietf.org/doc/html/rfc2119"><cite>Key words for use in RFCs to Indicate Requirement Levels</cite></a>. March 1997. Best Current Practice. URL: <a href="https://datatracker.ietf.org/doc/html/rfc2119">https://datatracker.ietf.org/doc/html/rfc2119</a> - <dt id="biblio-webidl">[WEBIDL] - <dd>Edgar Chen; Timothy Gu. <a href="https://webidl.spec.whatwg.org/"><cite>Web IDL Standard</cite></a>. Living Standard. URL: <a href="https://webidl.spec.whatwg.org/">https://webidl.spec.whatwg.org/</a> - </dl> - <h2 class="no-num no-ref heading settled" id="idl-index"><span class="content">IDL Index</span><a class="self-link" href="#idl-index"></a></h2> -<pre class="idl highlight def"><c- b>interface</c-> <a href="#attesterconnection"><code><c- g>AttesterConnection</c-></code></a> { - <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-ArrayBuffer"><c- b>ArrayBuffer</c-></a> <a href="#dom-attesterconnection-getattestation"><code><c- g>getAttestation</c-></code></a>(<a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-DOMString"><c- b>DOMString</c-></a> <a href="#dom-attesterconnection-getattestation-contentbinding-contentbinding"><code><c- g>contentBinding</c-></code></a>); -}; - -[<a class="idl-code" data-link-type="extended-attribute" href="https://webidl.spec.whatwg.org/#Exposed"><c- g>Exposed</c-></a>=<c- n>Window</c->] -<c- b>partial</c-> <c- b>interface</c-> <a class="idl-code" data-link-type="interface" href="https://html.spec.whatwg.org/multipage/system-state.html#navigator"><c- g>Navigator</c-></a> { - [<a class="idl-code" data-link-type="extended-attribute" href="https://webidl.spec.whatwg.org/#SecureContext"><c- g>SecureContext</c-></a>] <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-promise"><c- b>Promise</c-></a>&lt;<a data-link-type="idl-name" href="#environmentintegrity"><c- n>EnvironmentIntegrity</c-></a>> <a class="idl-code" data-link-type="method" href="#dom-navigator-getenvironmentintegrity"><c- g>getEnvironmentIntegrity</c-></a>(<a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-DOMString"><c- b>DOMString</c-></a> <a href="#dom-navigator-getenvironmentintegrity-contentbinding-contentbinding"><code><c- g>contentBinding</c-></code></a>); -}; - -<c- b>interface</c-> <a href="#environmentintegrity"><code><c- g>EnvironmentIntegrity</c-></code></a> { - <c- b>readonly</c-> <c- b>attribute</c-> <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-ArrayBuffer"><c- b>ArrayBuffer</c-></a> <a data-readonly data-type="ArrayBuffer" href="#dom-environmentintegrity-attestationtoken"><code><c- g>attestationToken</c-></code></a>; - <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-DOMString"><c- b>DOMString</c-></a> <a href="#dom-environmentintegrity-encode"><code><c- g>encode</c-></code></a>(); - <a class="idl-code" data-link-type="interface" href="https://webidl.spec.whatwg.org/#idl-object"><c- b>object</c-></a> <a href="#dom-environmentintegrity-tojson"><code><c- g>toJSON</c-></code></a>(); -}; - -</pre> -<script>/* Boilerplate: script-dfn-panel */ -"use strict"; -{ - const dfnsJson = window.dfnsJson || {}; - - function genDfnPanel({dfnID, url, dfnText, refSections, external}) { - return mk.aside({ - class: "dfn-panel", - id: `infopanel-for-${dfnID}`, - "data-for": dfnID, - "aria-labelled-by":`infopaneltitle-for-${dfnID}`, - }, - mk.span({id:`infopaneltitle-for-${dfnID}`, style:"display:none"}, - `Info about the '${dfnText}' ${external?"external":""} reference.`), - mk.a({href:url}, url), - mk.b({}, "Referenced in:"), - mk.ul({}, - ...refSections.map(section=> - mk.li({}, - ...section.refs.map((ref, refI)=> - [ - mk.a({ - href: `#${ref.id}` - }, - (refI == 0) ? section.title : `(${refI + 1})` - ), - " ", - ] - ), - ), - ), - ), - ); - } - - function genAllDfnPanels() { - for(const panelData of Object.values(window.dfnpanelData)) { - const dfnID = panelData.dfnID; - const dfn = document.getElementById(dfnID); - if(!dfn) { - console.log(`Can't find dfn#${dfnID}.`, panelData); - } else { - const panel = genDfnPanel(panelData); - append(document.body, panel); - insertDfnPopupAction(dfn, panel) - } - } - } - - document.addEventListener("DOMContentLoaded", ()=>{ - genAllDfnPanels(); - - // Add popup behavior to all dfns to show the corresponding dfn-panel. - var dfns = queryAll('.dfn-paneled'); - for(let dfn of dfns) { ; } - - document.body.addEventListener("click", (e) => { - // If not handled already, just hide all dfn panels. - hideAllDfnPanels(); - }); - }) - - - function hideAllDfnPanels() { - // Turn off any currently "on" or "activated" panels. - queryAll(".dfn-panel.on, .dfn-panel.activated").forEach(el=>hideDfnPanel(el)); - } - - function showDfnPanel(dfnPanel, dfn) { - hideAllDfnPanels(); // Only display one at this time. - dfn.setAttribute("aria-expanded", "true"); - dfnPanel.classList.add("on"); - dfnPanel.style.left = "5px"; - dfnPanel.style.top = "0px"; - const panelRect = dfnPanel.getBoundingClientRect(); - const panelWidth = panelRect.right - panelRect.left; - if (panelRect.right > document.body.scrollWidth) { - // Panel's overflowing the screen. - // Just drop it below the dfn and flip it rightward instead. - // This still wont' fix things if the screen is *really* wide, - // but fixing that's a lot harder without 'anchor()'. - dfnPanel.style.top = "1.5em"; - dfnPanel.style.left = "auto"; - dfnPanel.style.right = "0px"; - } - } - - function pinDfnPanel(dfnPanel) { - // Switch it to "activated" state, which pins it. - dfnPanel.classList.add("activated"); - dfnPanel.style.left = null; - dfnPanel.style.top = null; - } - - function hideDfnPanel(dfnPanel, dfn) { - if(!dfn) { - dfn = document.getElementById(dfnPanel.getAttribute("data-for")); - } - dfn.setAttribute("aria-expanded", "false") - dfnPanel.classList.remove("on"); - dfnPanel.classList.remove("activated"); - } - - function toggleDfnPanel(dfnPanel, dfn) { - if(dfnPanel.classList.contains("on")) { - hideDfnPanel(dfnPanel, dfn); - } else { - showDfnPanel(dfnPanel, dfn); - } - } - - function insertDfnPopupAction(dfn, dfnPanel) { - // Find dfn panel - const panelWrapper = document.createElement('span'); - panelWrapper.appendChild(dfnPanel); - panelWrapper.style.position = "relative"; - panelWrapper.style.height = "0px"; - dfn.insertAdjacentElement("afterend", panelWrapper); - dfn.setAttribute('role', 'button'); - dfn.setAttribute('aria-expanded', 'false') - dfn.tabIndex = 0; - dfn.classList.add('has-dfn-panel'); - dfn.addEventListener('click', (event) => { - showDfnPanel(dfnPanel, dfn); - event.stopPropagation(); - }); - dfn.addEventListener('keypress', (event) => { - const kc = event.keyCode; - // 32->Space, 13->Enter - if(kc == 32 || kc == 13) { - toggleDfnPanel(dfnPanel, dfn); - event.stopPropagation(); - event.preventDefault(); - } - }); - - dfnPanel.addEventListener('click', (event) => { - if (event.target.nodeName == 'A') { - pinDfnPanel(dfnPanel); - } - event.stopPropagation(); - }); - - dfnPanel.addEventListener('keydown', (event) => { - if(event.keyCode == 27) { // Escape key - hideDfnPanel(dfnPanel, dfn); - event.stopPropagation(); - event.preventDefault(); - } - }) - } -} -</script> -<script>/* Boilerplate: script-dfn-panel */ -"use strict"; -{ - const dfnsJson = window.dfnsJson || {}; - - function genDfnPanel({dfnID, url, dfnText, refSections, external}) { - return mk.aside({ - class: "dfn-panel", - id: `infopanel-for-${dfnID}`, - "data-for": dfnID, - "aria-labelled-by":`infopaneltitle-for-${dfnID}`, - }, - mk.span({id:`infopaneltitle-for-${dfnID}`, style:"display:none"}, - `Info about the '${dfnText}' ${external?"external":""} reference.`), - mk.a({href:url}, url), - mk.b({}, "Referenced in:"), - mk.ul({}, - ...refSections.map(section=> - mk.li({}, - ...section.refs.map((ref, refI)=> - [ - mk.a({ - href: `#${ref.id}` - }, - (refI == 0) ? section.title : `(${refI + 1})` - ), - " ", - ] - ), - ), - ), - ), - ); - } - - function genAllDfnPanels() { - for(const panelData of Object.values(window.dfnpanelData)) { - const dfnID = panelData.dfnID; - const dfn = document.getElementById(dfnID); - if(!dfn) { - console.log(`Can't find dfn#${dfnID}.`, panelData); - } else { - const panel = genDfnPanel(panelData); - append(document.body, panel); - insertDfnPopupAction(dfn, panel) - } - } - } - - document.addEventListener("DOMContentLoaded", ()=>{ - genAllDfnPanels(); - - // Add popup behavior to all dfns to show the corresponding dfn-panel. - var dfns = queryAll('.dfn-paneled'); - for(let dfn of dfns) { ; } - - document.body.addEventListener("click", (e) => { - // If not handled already, just hide all dfn panels. - hideAllDfnPanels(); - }); - }) - - - function hideAllDfnPanels() { - // Turn off any currently "on" or "activated" panels. - queryAll(".dfn-panel.on, .dfn-panel.activated").forEach(el=>hideDfnPanel(el)); - } - - function showDfnPanel(dfnPanel, dfn) { - hideAllDfnPanels(); // Only display one at this time. - dfn.setAttribute("aria-expanded", "true"); - dfnPanel.classList.add("on"); - dfnPanel.style.left = "5px"; - dfnPanel.style.top = "0px"; - const panelRect = dfnPanel.getBoundingClientRect(); - const panelWidth = panelRect.right - panelRect.left; - if (panelRect.right > document.body.scrollWidth) { - // Panel's overflowing the screen. - // Just drop it below the dfn and flip it rightward instead. - // This still wont' fix things if the screen is *really* wide, - // but fixing that's a lot harder without 'anchor()'. - dfnPanel.style.top = "1.5em"; - dfnPanel.style.left = "auto"; - dfnPanel.style.right = "0px"; - } - } - - function pinDfnPanel(dfnPanel) { - // Switch it to "activated" state, which pins it. - dfnPanel.classList.add("activated"); - dfnPanel.style.left = null; - dfnPanel.style.top = null; - } - - function hideDfnPanel(dfnPanel, dfn) { - if(!dfn) { - dfn = document.getElementById(dfnPanel.getAttribute("data-for")); - } - dfn.setAttribute("aria-expanded", "false") - dfnPanel.classList.remove("on"); - dfnPanel.classList.remove("activated"); - } - - function toggleDfnPanel(dfnPanel, dfn) { - if(dfnPanel.classList.contains("on")) { - hideDfnPanel(dfnPanel, dfn); - } else { - showDfnPanel(dfnPanel, dfn); - } - } - - function insertDfnPopupAction(dfn, dfnPanel) { - // Find dfn panel - const panelWrapper = document.createElement('span'); - panelWrapper.appendChild(dfnPanel); - panelWrapper.style.position = "relative"; - panelWrapper.style.height = "0px"; - dfn.insertAdjacentElement("afterend", panelWrapper); - dfn.setAttribute('role', 'button'); - dfn.setAttribute('aria-expanded', 'false') - dfn.tabIndex = 0; - dfn.classList.add('has-dfn-panel'); - dfn.addEventListener('click', (event) => { - showDfnPanel(dfnPanel, dfn); - event.stopPropagation(); - }); - dfn.addEventListener('keypress', (event) => { - const kc = event.keyCode; - // 32->Space, 13->Enter - if(kc == 32 || kc == 13) { - toggleDfnPanel(dfnPanel, dfn); - event.stopPropagation(); - event.preventDefault(); - } - }); - - dfnPanel.addEventListener('click', (event) => { - if (event.target.nodeName == 'A') { - pinDfnPanel(dfnPanel); - } - event.stopPropagation(); - }); - - dfnPanel.addEventListener('keydown', (event) => { - if(event.keyCode == 27) { // Escape key - hideDfnPanel(dfnPanel, dfn); - event.stopPropagation(); - event.preventDefault(); - } - }) - } -} -</script> -<script>/* Boilerplate: script-dfn-panel-json */ -window.dfnpanelData = {}; -window.dfnpanelData['be0c27b2'] = {"dfnID": "be0c27b2", "url": "https://html.spec.whatwg.org/multipage/system-state.html#navigator", "dfnText": "Navigator", "refSections": [{"refs": [{"id": "ref-for-navigator"}, {"id": "ref-for-navigator\u2460"}], "title": "4.1. Extensions to Navigator"}], "external": true}; -window.dfnpanelData['a72449dd'] = {"dfnID": "a72449dd", "url": "https://html.spec.whatwg.org/multipage/infrastructure.html#in-parallel", "dfnText": "in parallel", "refSections": [{"refs": [{"id": "ref-for-in-parallel"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": true}; -window.dfnpanelData['6d19ac93'] = {"dfnID": "6d19ac93", "url": "https://infra.spec.whatwg.org/#user-agent", "dfnText": "user agent", "refSections": [{"refs": [{"id": "ref-for-user-agent"}, {"id": "ref-for-user-agent\u2460"}, {"id": "ref-for-user-agent\u2461"}], "title": "3. Attesters"}, {"refs": [{"id": "ref-for-user-agent\u2462"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": true}; -window.dfnpanelData['2f8afbfe'] = {"dfnID": "2f8afbfe", "url": "https://webidl.spec.whatwg.org/#idl-ArrayBuffer", "dfnText": "ArrayBuffer", "refSections": [{"refs": [{"id": "ref-for-idl-ArrayBuffer"}], "title": "3.3. AttesterConnection"}, {"refs": [{"id": "ref-for-idl-ArrayBuffer\u2460"}], "title": "4.2. EnvironmentIntegrity"}], "external": true}; -window.dfnpanelData['8855a9aa'] = {"dfnID": "8855a9aa", "url": "https://webidl.spec.whatwg.org/#idl-DOMString", "dfnText": "DOMString", "refSections": [{"refs": [{"id": "ref-for-idl-DOMString"}], "title": "3.3. AttesterConnection"}, {"refs": [{"id": "ref-for-idl-DOMString\u2460"}], "title": "4.1. Extensions to Navigator"}, {"refs": [{"id": "ref-for-idl-DOMString\u2461"}], "title": "4.2. EnvironmentIntegrity"}], "external": true}; -window.dfnpanelData['889e932f'] = {"dfnID": "889e932f", "url": "https://webidl.spec.whatwg.org/#Exposed", "dfnText": "Exposed", "refSections": [{"refs": [{"id": "ref-for-Exposed"}], "title": "4.1. Extensions to Navigator"}], "external": true}; -window.dfnpanelData['bdbd19d1'] = {"dfnID": "bdbd19d1", "url": "https://webidl.spec.whatwg.org/#idl-promise", "dfnText": "Promise", "refSections": [{"refs": [{"id": "ref-for-idl-promise"}], "title": "4.1. Extensions to Navigator"}], "external": true}; -window.dfnpanelData['b75bb3bd'] = {"dfnID": "b75bb3bd", "url": "https://webidl.spec.whatwg.org/#SecureContext", "dfnText": "SecureContext", "refSections": [{"refs": [{"id": "ref-for-SecureContext"}], "title": "4.1. Extensions to Navigator"}], "external": true}; -window.dfnpanelData['dacde8b5'] = {"dfnID": "dacde8b5", "url": "https://webidl.spec.whatwg.org/#a-new-promise", "dfnText": "a new promise", "refSections": [{"refs": [{"id": "ref-for-a-new-promise"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": true}; -window.dfnpanelData['cd787c3f'] = {"dfnID": "cd787c3f", "url": "https://webidl.spec.whatwg.org/#dfn-exception", "dfnText": "exception", "refSections": [{"refs": [{"id": "ref-for-dfn-exception"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": true}; -window.dfnpanelData['efd1ec5d'] = {"dfnID": "efd1ec5d", "url": "https://webidl.spec.whatwg.org/#idl-object", "dfnText": "object", "refSections": [{"refs": [{"id": "ref-for-idl-object"}], "title": "4.2. EnvironmentIntegrity"}], "external": true}; -window.dfnpanelData['b262501e'] = {"dfnID": "b262501e", "url": "https://webidl.spec.whatwg.org/#reject", "dfnText": "reject", "refSections": [{"refs": [{"id": "ref-for-reject"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": true}; -window.dfnpanelData['3b90bdcd'] = {"dfnID": "3b90bdcd", "url": "https://webidl.spec.whatwg.org/#resolve", "dfnText": "resolve", "refSections": [{"refs": [{"id": "ref-for-resolve"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": true}; -window.dfnpanelData['web-environment-web-environment'] = {"dfnID": "web-environment-web-environment", "url": "#web-environment-web-environment", "dfnText": "web environment", "refSections": [{"refs": [{"id": "ref-for-web-environment-web-environment"}], "title": "3. Attesters"}], "external": false}; -window.dfnpanelData['attester-attester'] = {"dfnID": "attester-attester", "url": "#attester-attester", "dfnText": "attester", "refSections": [{"refs": [{"id": "ref-for-attester-attester"}, {"id": "ref-for-attester-attester\u2460"}], "title": "3. Attesters"}, {"refs": [{"id": "ref-for-attester-attester\u2461"}], "title": "3.3. AttesterConnection"}, {"refs": [{"id": "ref-for-attester-attester\u2462"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": false}; -window.dfnpanelData['integrity-verdict-integrity-verdict'] = {"dfnID": "integrity-verdict-integrity-verdict", "url": "#integrity-verdict-integrity-verdict", "dfnText": "Integrity verdict", "refSections": [{"refs": [{"id": "ref-for-integrity-verdict-integrity-verdict"}, {"id": "ref-for-integrity-verdict-integrity-verdict\u2460"}], "title": "3. Attesters"}, {"refs": [{"id": "ref-for-integrity-verdict-integrity-verdict\u2461"}], "title": "3.3. AttesterConnection"}], "external": false}; -window.dfnpanelData['attesterconnection'] = {"dfnID": "attesterconnection", "url": "#attesterconnection", "dfnText": "AttesterConnection", "refSections": [{"refs": [{"id": "ref-for-attesterconnection"}, {"id": "ref-for-attesterconnection\u2460"}, {"id": "ref-for-attesterconnection\u2461"}], "title": "3. Attesters"}, {"refs": [{"id": "ref-for-attesterconnection\u2462"}], "title": "3.3. AttesterConnection"}, {"refs": [{"id": "ref-for-attesterconnection\u2463"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": false}; -window.dfnpanelData['dom-attesterconnection-getattestation'] = {"dfnID": "dom-attesterconnection-getattestation", "url": "#dom-attesterconnection-getattestation", "dfnText": "getAttestation", "refSections": [{"refs": [{"id": "ref-for-dom-attesterconnection-getattestation"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": false}; -window.dfnpanelData['attesterconnection-attesterconnection'] = {"dfnID": "attesterconnection-attesterconnection", "url": "#attesterconnection-attesterconnection", "dfnText": "attesterConnection", "refSections": [{"refs": [{"id": "ref-for-attesterconnection-attesterconnection"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": false}; -window.dfnpanelData['dom-navigator-getenvironmentintegrity'] = {"dfnID": "dom-navigator-getenvironmentintegrity", "url": "#dom-navigator-getenvironmentintegrity", "dfnText": "getEnvironmentIntegrity(contentBinding)", "refSections": [{"refs": [{"id": "ref-for-dom-navigator-getenvironmentintegrity"}], "title": "4.1. Extensions to Navigator"}, {"refs": [{"id": "ref-for-dom-navigator-getenvironmentintegrity\u2460"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": false}; -window.dfnpanelData['environmentintegrity'] = {"dfnID": "environmentintegrity", "url": "#environmentintegrity", "dfnText": "EnvironmentIntegrity", "refSections": [{"refs": [{"id": "ref-for-environmentintegrity"}], "title": "4.1. Extensions to Navigator"}, {"refs": [{"id": "ref-for-environmentintegrity\u2460"}], "title": "4.1.1. getEnvironmentIntegrity()"}, {"refs": [{"id": "ref-for-environmentintegrity\u2461"}], "title": "4.2. EnvironmentIntegrity"}], "external": false}; -window.dfnpanelData['dom-environmentintegrity-attestationtoken'] = {"dfnID": "dom-environmentintegrity-attestationtoken", "url": "#dom-environmentintegrity-attestationtoken", "dfnText": "attestationToken", "refSections": [{"refs": [{"id": "ref-for-dom-environmentintegrity-attestationtoken"}], "title": "4.1.1. getEnvironmentIntegrity()"}], "external": false}; -</script> -<script>/* Boilerplate: script-dom-helper */ -function query(sel) { return document.querySelector(sel); } - -function queryAll(sel) { return [...document.querySelectorAll(sel)]; } - -function iter(obj) { - if(!obj) return []; - var it = obj[Symbol.iterator]; - if(it) return it; - return Object.entries(obj); -} - -function mk(tagname, attrs, ...children) { - const el = document.createElement(tagname); - for(const [k,v] of iter(attrs)) { - if(k.slice(0,3) == "_on") { - const eventName = k.slice(3); - el.addEventListener(eventName, v); - } else if(k[0] == "_") { - // property, not attribute - el[k.slice(1)] = v; - } else { - if(v === false || v == null) { - continue; - } else if(v === true) { - el.setAttribute(k, ""); - continue; - } else { - el.setAttribute(k, v); - } - } - } - append(el, children); - return el; -} - -/* Create shortcuts for every known HTML element */ -[ - "a", - "abbr", - "acronym", - "address", - "applet", - "area", - "article", - "aside", - "audio", - "b", - "base", - "basefont", - "bdo", - "big", - "blockquote", - "body", - "br", - "button", - "canvas", - "caption", - "center", - "cite", - "code", - "col", - "colgroup", - "datalist", - "dd", - "del", - "details", - "dfn", - "dialog", - "div", - "dl", - "dt", - "em", - "embed", - "fieldset", - "figcaption", - "figure", - "font", - "footer", - "form", - "frame", - "frameset", - "head", - "header", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "hr", - "html", - "i", - "iframe", - "img", - "input", - "ins", - "kbd", - "label", - "legend", - "li", - "link", - "main", - "map", - "mark", - "meta", - "meter", - "nav", - "nobr", - "noscript", - "object", - "ol", - "optgroup", - "option", - "output", - "p", - "param", - "pre", - "progress", - "q", - "s", - "samp", - "script", - "section", - "select", - "small", - "source", - "span", - "strike", - "strong", - "style", - "sub", - "summary", - "sup", - "table", - "tbody", - "td", - "template", - "textarea", - "tfoot", - "th", - "thead", - "time", - "title", - "tr", - "u", - "ul", - "var", - "video", - "wbr", - "xmp", -].forEach(tagname=>{ - mk[tagname] = (...args) => mk(tagname, ...args); -}); - -function* nodesFromChildList(children) { - for(const child of children.flat(Infinity)) { - if(child instanceof Node) { - yield child; - } else { - yield new Text(child); - } - } -} -function append(el, ...children) { - for(const child of nodesFromChildList(children)) { - if(el instanceof Node) el.appendChild(child); - else el.push(child); - } - return el; -} - -function insertAfter(el, ...children) { - for(const child of nodesFromChildList(children)) { - el.parentNode.insertBefore(child, el.nextSibling); - } - return el; -} - -function clearContents(el) { - el.innerHTML = ""; - return el; -} - -function parseHTML(markup) { - if(markup.toLowerCase().trim().indexOf('<!doctype') === 0) { - const doc = document.implementation.createHTMLDocument(""); - doc.documentElement.innerHTML = markup; - return doc; - } else { - const el = mk.template({}); - el.innerHTML = markup; - return el.content; - } -} -</script> -<script>/* Boilerplate: script-var-click-highlighting */ -/* -Color-choosing design: - -Colors are ordered by goodness. -Each color has a usage count (initially zero). -Each variable has a last-used color. - -* If the var has a last-used color, and that color's usage is 0, - return that color. -* Otherwise, return the lowest-indexed color with the lowest usage. - Increment the color's usage and set it as the last-used color - for that var. -* On unclicking, decrement usage of the color. -*/ -"use strict"; -{ - document.addEventListener("click", e=>{ - if(e.target.nodeName == "VAR") { - highlightSameAlgoVars(e.target); - } - }); - const indexCounts = new Map(); - const indexNames = new Map(); - function highlightSameAlgoVars(v) { - // Find the algorithm container. - let algoContainer = null; - let searchEl = v; - while(algoContainer == null && searchEl != document.body) { - searchEl = searchEl.parentNode; - if(searchEl.hasAttribute("data-algorithm")) { - algoContainer = searchEl; - } - } - - // Not highlighting document-global vars, - // too likely to be unrelated. - if(algoContainer == null) return; - - const algoName = algoContainer.getAttribute("data-algorithm"); - const varName = getVarName(v); - const addClass = !v.classList.contains("selected"); - let highlightClass = null; - if(addClass) { - const index = chooseHighlightIndex(algoName, varName); - indexCounts.get(algoName)[index] += 1; - indexNames.set(algoName+"///"+varName, index); - highlightClass = nameFromIndex(index); - } else { - const index = previousHighlightIndex(algoName, varName); - indexCounts.get(algoName)[index] -= 1; - highlightClass = nameFromIndex(index); - } - - // Find all same-name vars, and toggle their class appropriately. - for(const el of algoContainer.querySelectorAll("var")) { - if(getVarName(el) == varName) { - el.classList.toggle("selected", addClass); - el.classList.toggle(highlightClass, addClass); - } - } - } - function getVarName(el) { - return el.textContent.replace(/(\s|\xa0)+/, " ").trim(); - } - function chooseHighlightIndex(algoName, varName) { - let indexes = null; - if(indexCounts.has(algoName)) { - indexes = indexCounts.get(algoName); - } else { - // 7 classes right now - indexes = [0,0,0,0,0,0,0]; - indexCounts.set(algoName, indexes); - } - - // If the element was recently unclicked, - // *and* that color is still unclaimed, - // give it back the same color. - const lastIndex = previousHighlightIndex(algoName, varName); - if(indexes[lastIndex] === 0) return lastIndex; - - // Find the earliest index with the lowest count. - const minCount = Math.min.apply(null, indexes); - let index = null; - for(var i = 0; i < indexes.length; i++) { - if(indexes[i] == minCount) { - return i; - } - } - } - function previousHighlightIndex(algoName, varName) { - return indexNames.get(algoName+"///"+varName); - } - function nameFromIndex(index) { - return "selected" + index; - } -} -</script> \ No newline at end of file