wintercg / proposal-common-minimum-api

https://common-min-api.proposal.wintercg.org/
Other
227 stars 13 forks source link

Navigator.userAgent #4

Closed legendecas closed 1 year ago

legendecas commented 2 years ago

Content of Navigator.userAgent is not reliable and identity detection based on it is not recommended.

By looking at the APIs that are already implemented and supported in common across Node.js, Deno, and Cloudflare Workers. If there were at least two implementations among those -- either already supported or in progress -- then it was added to the list.

The bar documented says we need at least 2 implementations interested in the API to add it to the list. But I don't see any one of these runtimes have implemented this API.

panva commented 2 years ago

I believe userAgent and/or userAgentData have a place in Non-Browser JavaScript-based runtime environments as means for universal javascript libraries to detect their runtime and accommodate either quirks, non-conformities, or even utilize platform-specific features.

One such example is detecting the CF Workers runtime in order to work around the inability/edge cases of awaiting Promise that was not created in the current execution context.

Another is the ability to use vendor-specific proprietary extensions in Web Crypto API.

ljharb commented 2 years ago

Instead of replicating this very problematic API and approach, why not come up with a new standard here that would actually be designed for this purpose? User agents shouldn’t be propagated, they should be deprecated.

jasnell commented 2 years ago

Yeah this is one that is definitely questionable. The key reason for going with navigator.userAgent right now is this tweet from @domenic: https://twitter.com/domenic/status/1433851725476245507 image

jasnell commented 2 years ago

Cloudflare Workers has implemented navigator.userAgent and I believe deno had the intent of doing so (@lucacasonato can confirm whether that is correct or not), so I went ahead and added it to the list... but we do need to get clarification.

@ljharb ... One detail, the point of the common api spec is not to create new API but to document the existing apis that the runtimes should have in common. If we want to come up with a new API, then that will be a separate proposal that should be ultimately targeted at the WHATWG to discuss

lucacasonato commented 2 years ago

Yup, we are implementing this very soon.

ljharb commented 2 years ago

@jasnell thanks, that's good clarification. I would hope that in general, the group would be very cautious about including an API when there might be a better alternative worth proposing to WHATWG.

jasnell commented 2 years ago

the group would be very cautious about including an API when there might be a better alternative worth proposing to WHATWG.

That's a key part of this exercise. There's a balance between current status quo and identifying what other proposals should be put on the table. The next step for this one in particular would be to work up a proposal for a navigator.userAgent alternative that can be submitted to the WHATWG for consideration. If WHATWG declines on considering it, then we can fall back and consider it ourselves here.

domenic commented 2 years ago

To be clear, navigator.userAgent is not considered problematic or to be avoided or deprecated from the perspective of the web standards community. Chromium has proposed a version (userAgentData) with less string parsing but it's unclear whether that will be implemented elsewhere. I don't think there's much room for other things in this space for web standards, although as with other server-side APIs the exact way in which the web specs are interpreted or violated is a good question for this group. (E.g., the web user agent spec says every user agent must start with "Mozilla/5.0", but maybe that's not something server runtimes want to follow.)

jasnell commented 2 years ago

I'd second that to say that navigator.userAgent works perfectly well in the Workers case. We currently just set the value to 'Cloudflare-Workers', ignoring the web user agent spec bit about leading with Mozilla/5.0. It works for the use case we have.

maxshirshin commented 2 years ago

Am I right that naming is the biggest issue? :) "navigator" doesn't sound right for a server runtime. However, since navigator is actually a Navigator instance (or, to be precise, conforms to the Navigator interface), could we consider choosing a different global name while staying compatible with the interface?

jasnell commented 2 years ago

I don't think naming is really much of an issue at all. There's just a ton of history around the "user agent" string format (which we don't actually need for non-browser environments) and the fact that there's a lot of code that will just use the presence of the navigator global as an imperfect heuristic check to determine if they are running in a browser or not.

panva commented 2 years ago

Deno now includes navigator.userAgent available on the global scope.

➜ deno                              
Deno 1.22.0
exit using ctrl+d or close()

> navigator.userAgent
"Deno/1.22.0"
jasnell commented 2 years ago

We discussed this on the last wintercg call. Where we landed is that Web-interoperable runtimes should generally treat the navigator.userAgent as an opaque string. If an implementation wishes to provide more detailed structured data, then it should use the navigator.userAgentData API to do so.

For the minimum common api doc, I plan to add a section discussing the basic format here. To review, RFC 7231 defines the format of the string as:

User-Agent = product *( RWS (product / comment ) )
product = token ["/" product-version]
product-version = token

The minimum api doc will specify that the bare minimum requirement is a single product token as the value with no version. For instance, Cloudflare Workers uses just navigator.userAgent = 'Cloudflare-Workers'.

We want to discourage parsing of the value as much as possible given all the problems there have been historically with User-Agent strings.

legendecas commented 2 years ago

The minimum api doc will specify that the bare minimum requirement is a single product token as the value with no version. For instance, Cloudflare Workers uses just navigator.userAgent = 'Cloudflare-Workers'.

I'd find this can be another problem for APM vendors to collect userAgent as auxiliary data for human-readable purposes. For instance, if runtimes didn't include their version in the userAgent string, they'll eventually have to check that against the userAgent string content (as browsers put their version in the userAgent) and try to get the information by other means, either runtime specific or by userAgentData. If all runtimes put their versions in the userAgent, then userAgentData or other runtime-specific means are not necessary in the case.

I would be interested in the considerations of why we should not put versions in the userAgent string :).

Tseian commented 1 year ago

In Bytedance, Hourai.js navigator.userAgent string content is make of Hourai.js/${version} ${product name}.