Refuse an origin the grant could never have named

The identity line elides a long host from the left, keeping the
registrable domain visible, which it does with `direction: rtl`. That is
sound for a host — every character in one resolves left-to-right, so the
string reads in source order — but it is not sound for arbitrary text,
whose neutral and RTL runs can render in an order they were not written
in. On the one line of this dialog whose whole job is saying who is
asking, that is the wrong thing to be lenient about.

The entity resolver reached that state through its own fallback: when
`new URL(origin)` threw it displayed the unparsed string and still marked
it as a host. An origin the server cannot parse cannot name a grant
target either — `AuthService#originFromUrl` rejects it, and rejects
non-http(s) schemes with it — so there was never anything to prompt
about. Deny at the gate, next to the existing "requester the grant can't
name" check, on the same test the server applies.
This commit is contained in:
jelveh
2026-07-26 17:08:56 -07:00
parent 7a9749ad32
commit bfc61a8c39
+29
View File
@@ -71,6 +71,18 @@ async function UIPermissionDialog (options) {
return false;
}
// An origin the server would refuse to parse can't name a grant target
// either, so there is nothing to prompt about — and showing it anyway would
// put a string that is not a host into the identity line, which is styled to
// elide *hosts* from the left (`direction: rtl`). Arbitrary text there can
// render in an order it wasn't written in, on the one line of this dialog
// whose whole job is saying who is asking. Mirrors the server's own check in
// AuthService#originFromUrl: parseable, and http(s).
if ( options.origin && ! is_web_origin(options.origin) ) {
console.error('Permission dialog: unusable origin', options.origin);
return false;
}
// `||`, not `??`: the gate above treats an empty uid as absent, so the key
// has to fall through to the origin too — otherwise two different origins
// arriving with a blank uid would share one decision.
@@ -326,6 +338,23 @@ async function undo_uncertain_grant (options) {
}
}
/**
* Whether `origin` is a real web origin: something `new URL()` accepts, on a
* scheme the platform actually serves apps over. `new URL()` alone is far too
* permissive here — it happily parses `javascript:`, `data:` and `file:`.
*
* @param {string} origin
* @returns {boolean}
*/
function is_web_origin (origin) {
try {
const { protocol } = new URL(origin);
return protocol === 'https:' || protocol === 'http:';
} catch (e) {
return false;
}
}
/**
* Resolves `promise`, or `fallback` if it hasn't settled within `ms`.
*