links: gate a url by its scheme, not its spelling - #11
Merged
Conversation
HTTPS:// failed the gate, so the link shipped as href="#": underlined, clickable and dead. That is the shape that cost a mailto purchase route. A refused url now degrades to its own words and the build names the file and the url, instead of the page looking fine and going nowhere. The checkout validator and absUrl move with the gate; a validator stricter than the emitter turns a working HTTPS:// checkout into "Checkout coming soon". Urls in store.config.json fail the build, prose only warns: one is a small hand-edited file, the other is a stranger's writing.
…parser Found by fuzzing the gate rather than reading it: "https://" satisfies the scheme prefix, has no host, and shipped as an underlined link that goes nowhere. Same dead link the "#" fallback made, arriving through the accept path, so removing "#" alone did not close the class. store.config.json's own "url" check has demanded a host since before the gate did. The image sinks now emit the url safeUrl approved rather than the one they were handed, so validate and emit cannot read different strings. Tests pin the outcome against the WHATWG parser Node ships, not against substrings of our own html: every accepted url must resolve to this origin, an explicit http(s) url, or a mailto. A fragment is a link target and never an image src, which nothing was holding.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
HTTPS://example.comfailed the url gate, so the link shipped ashref="#": underlined, clickable and dead. Nothing in the repo is written that way today, which made it a trap rather than a live defect, but the identical shape had already cost a purchase route when amailto:the gate did not allow degraded the same way.Two changes, and a class settled.
The scheme is read case-insensitively. The two validators in
build.jsalready were (c.urlsince before this branch, with a comment citing RFC 3986); only the gate that actually emits hrefs disagreed. The checkout validator andabsUrlmove with it, because a validator stricter than the emitter turns a workingHTTPS://checkout into "Checkout coming soon".href="#"stops being the answer to a refused url. It degrades to its own words instead: visible, unclickable, honest. The build then names the file and the url, so a green build cannot hide it the way#did.An http(s) url with no host is refused. Found by fuzzing rather than reading:
https://satisfies any scheme prefix, has no host and navigates nowhere, so it produced the same dead link through the accept path. Removing#alone did not close the class.Where the failure lands differs on purpose: a url in
store.config.jsonfails the build (one small hand-edited file, nine other fatal checks beside it, and a refused item url now drops a whole figure silently). A url in prose only warns, because this repo is forked and run by strangers on their own writing and refusing to deploy a store over one bad link in one paragraph costs them more than it saves.Evidence
Differential against the gate at 30b4be6, 1,148,904 inputs in both link and src modes:
Resolution is checked with the WHATWG parser Node ships rather than by matching substrings of our own html, and that property is now in the suite: every accepted url must resolve to this origin, an explicit http(s) url, or a mailto. 197,904 hostile inputs (mixed case, tabs, newlines, NUL, vertical tab, protocol-relative in every spelling) are refused in both modes.
20 guards were mutation-tested; 17 go red. The three that do not are reported in the branch notes, one of which was a real gap in
#-as-an-image-src and is now covered.