w3c / gamepad

Gamepad
https://w3c.github.io/gamepad/
Other
139 stars 49 forks source link

id field in gamepad might have a persistent identifier? #73

Open tomrittervg opened 6 years ago

tomrittervg commented 6 years ago

(See also the email thread)

I have read in the past that the id field sometimes contains things like a serial number. Obviously this presents a very persistent tracking identifier.

Mozilla says: in Firefox it will contain three pieces of information separated by dashes (-): Two 4-digit hexadecimal strings containing the USB vendor and product id of the controller The name of the controller as provided by the driver. https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/id

How is this exposed in other browsers? It seems like it would be advantageous to require this string to not contain uniquely identifying information and to Non-normatively suggest an algorithm to do so.

Florian suggest that we standardize the id attribute so the vendor and device id are in a consistent format and order.

He also indicated that the product name is displayed to the user to help them identify the control (they won't know vendor/device id of course.)

My concern is still that the product name may contain serial numbers or something similar that would uniquely identify a particular controller vs merely identifying it as that type of controller. Have other people seen this behavior? It seems it would be near-impossible to fix on the controller side (since it'd require controllers to be reflashed with new firmware...)

luser commented 6 years ago

Some related issues: https://github.com/w3c/gamepad/issues/65 https://github.com/w3c/gamepad/issues/9 https://github.com/w3c/gamepad/issues/7

In general the id field is terrible (sorry). We should expose the vendor + product IDs in separate fields if available, and the controller name in its own field. The product id that MDN talks about is in terms of the USB device desciptor, where AFAICT it is intended to be the product name. For the purposes of the Gamepad API we simply want "a human-readable string that describes the device so that users can distinguish multiple connected devices".

nondebug commented 6 years ago

Exposing vendor/product ID as (integer) fields would be a major help for developers who are trying to support device-specific gamepad features and calibration. For instance, some gamepads have buttons not represented by the Standard Gamepad spec, and using them effectively usually requires identifying the gamepad model to understand how the buttons are positioned and labeled.

One issue is that these IDs aren't available for all APIs. XInput on Windows makes it difficult to identify specific devices, and as a result many browsers report any XInput device as a generic Xbox 360 controller. This makes it difficult to give (e.g.) Xbox One-specific button prompts when the user has an Xbox One controller.

Some devices have multiple vendor/product IDs but should be treated as a single device, and it's not always obvious which ID pair is the most appropriate:

In principle, vendor/product IDs could still expose personally identifiable information if the device chooses its own ID or is an extremely rare device. To avoid revealing too much information, perhaps the vendor/product IDs should only be exposed when the IDs are present in a whitelist of known devices.

barryleiba commented 6 years ago

I'm very much not a fan of product identification strings as they expose privacy issues, security issues, and interoperability issues:

-- Privacy: Apart from the persistent identifier that's already been mentioned, the vendor/model/serial sort of information tells any application that can query it about a product the user bought, including an approximation of the date the user bought it (from the serial number).

-- Security: Attackers that can get this information can use it to identify vulnerable products that may then be targeted for attacks.

-- Interoperability: Such vendor strings encourage development of vendor-specific and even product-specific code to implement custom features and/or work around transient bugs. Such code often inds up going beyond its intended scope and causes difficult-to-debug interoperability problems.

If the point here is to simply identify devices to distinguish among, say, multiple game controllers that a user has around, a better solution is to allow the user to give her own names to the devices. The game can then tell the user to "pick up Lucille", or the user can say, "find Mjölnir", and none of the above issues arise.

luser commented 6 years ago

There are two issues at play here:

  1. Being able to distinguish between different devices. Consoles (which only support the manufacturer's standard controllers) have mostly settled on having LEDs to indicate player 1-4 on the controller itself. Having some way to indicate the device is critical if the user connects more than one controller.
  2. Being able to take arbitrary devices and map their inputs to known quantities, like "button 1 on this device is the A button and it is the primary action button". Providing the vendor and product IDs allows content pages to use JS libraries to provide this functionality. I wrote a prototype of such a library along with a small data set of controllers I had. Not having this ability means that either browsers have to maintain these mappings, or each webapp has to ask the user to map their controls, neither of which are great.

I don't think pushing this functionality up into the browser is a good idea either--browsers are hard to change, content pages can easily iterate on this sort of functionality.

npdoty commented 6 years ago

Being able to distinguish between different devices. Consoles (which only support the manufacturer's standard controllers) have mostly settled on having LEDs to indicate player 1-4 on the controller itself. Having some way to indicate the device is critical if the user connects more than one controller.

I think I understand this use case, but I'm not sure the unique identifier string is a very effective solution. It doesn't provide a signal on the controller itself (as you suggest is now common practice on consoles), and the names may not be very human-usable at all (which of my controllers is 810-3-USB Gamepad? what if I have four XBox One controllers connected?). Consoles used to address this by having the players press buttons in some order and then assigning that controller a temporary handle (Player 1) or color. That seems like it would work better than displaying an id field and handle a wider range of situations. And it's similar to @barryleiba's user-provided nickname approach without requiring user agent implementation. (However, it wouldn't easily persist nicknames across sessions, which I think is also a privacy advantage.)

npdoty commented 6 years ago

It might also make sense to have id (or corresponding broken out fields for descriptor/name and the vendor and product identifiers) as an optional field, if it's needed for certain use cases where a site wants to provide customized functionality for users with particular hardware.

I can imagine that a user in a private browsing mode or a user with a particular threat model where anonymity is important would not want to reveal the hardware identifier at all, but could still effectively use a gamepad, especially one that used a standard mapping. And where an implementation doesn't want to or can't provide detailed vendor/serial information or can't provide a useful human-readable name, we should prepare sites using the API for those fields not to be present.

cvan commented 5 years ago

It might also make sense to have id (or corresponding broken out fields for descriptor/name and the vendor and product identifiers) as an optional field, if it's needed for certain use cases where a site wants to provide customized functionality for users with particular hardware.

I like this.

And where an implementation doesn't want to or can't provide detailed vendor/serial information or can't provide a useful human-readable name, we should prepare sites using the API for those fields not to be present.

I agree. I think it probably makes sense to remove the id language from the spec and from the WebIDL schema for the Gamepad object.

On a related note, for the WebXR APIs, there's a proposal for maintaining a system of gamepad mappings (which is more relevant for issue #7), which I bring up because the proposal is to key off of the Gamepad#id.

I propose we remove id – and if absolutely necessary we could add vendor and productId. For reasons explained in comments above, ideally web developers and frameworks do not sniff for Gamepad#id (or a possible Gamepad#vendor + Gamepad#productId) but instead use feature detection of gamepad mappings and support inferred from Gamepad#buttons, Gamepad#axes, etc.

Also, want to reiterate that the discussion in issue #9 is very similar to the topics addressed in this issue. Perhaps we could close issue #9, forward-duping it to this issue?

sagoston commented 4 years ago

While Gamepad#id is not ideal, especially with the same controller getting a different id reported on different browsers, there is a use case we must support. When a game needs to display a help screen which shows which button/axis performs which game action, the game UI replies on know what type of controller is being used. Here's an example:

https://www.reddit.com/r/SteamController/comments/693sb6/prey_2017_has_native_steam_controller_api_support/

I agree that feature detection should be used but we cannot simply drop this field. I don't know if we can always rely on vendor/product ids being available with some of the underlying native APIs.

Any proposals for how we can at least make the id field consistent across browser implementations?

npdoty commented 4 years ago

Splitting id into vendor and productId would help with the interoperability/consistency concern. Marking the fields as optional and making it clear to sites that they may not be present would help with the privacy concern. Even the example Reddit thread showing a particular vendor's gamepad image in the control-setting UI includes people discussing the fact that sometimes (for example, Windows 10 and XInput) a generic controller will be used.

sagoston commented 4 years ago

@tomrittervg Created this PR, hopefully it address your original concerns: https://github.com/w3c/gamepad/pull/96

marcoscaceres commented 4 years ago

Discussed this with @sagoston, I wonder if we can do this incrementally: Presumedly, we have .id being exposed to a third-party via iframes, allowing id to become a fingerprinting vector for trackers.

So what if we added a feature policy to prevent third parties from accessing game pads unless the top-level document explicitly says it's ok? That would mitigate some of the privacy concerns and limit some of the damage.

We could then look at minting session-based identifiers for devices on a per origin basis (could just be 1-N). That would allow connection/disconnection of game pads, while providing a stable identifier for each game pad.

We could then look at adding a richer set of gamepad info, but we could gate it on a permission + user gesture.

That would leave the user in control of sharing a rich set of details about the game pad. The site could then explain why it needs that information ("to effectively map the game buttons" or whatever).

cvan commented 4 years ago

this is a good idea. do we have telemetry from the respective browsers on cross-origin usage of Gamepad#id? (I would assume it's close to zero.) would navigator.getGamepads() throw a NotAllowedError exception if a cross-origin document calls Gamepad#id as <iframe src="https://example.com/page-using-the-gamepad-api"></iframe> vs. <iframe src="https://example.com/page-using-the-gamepad-api" allow="gamepad"></iframe>?

luser commented 4 years ago

I think the issues I raised in my previous comment are still relevant. Maybe simply disallowing Gamepad access in third-party iframes would be sufficient? The spec was written with the intent being that only pages that were visible while the user interacted with a gamepad (like pressing a button) should get access to gamepads at all so I don't think this is unreasonable. In that case I think getGamepads() ought to just return an empty array.

Inventing a stable per-origin identifier for each gamepad is a clever idea, that would allow pages to save data like button mappings for a gamepad without cross-site info leaks.

marcoscaceres commented 4 years ago

We've submitted #112 for feature policy integration and https://github.com/w3c/permissions/pull/200 for permission API integration.

Would appreciate feedback.

mrmcpowned commented 4 years ago

We could then look at minting session-based identifiers for devices on a per origin basis (could just be 1-N). That would allow connection/disconnection of game pads, while providing a stable identifier for each game pad.

I like this idea since it could help solve the enumeration persistence issue. The ID's can be mapped to enumerated slots on a first-come, first-served basis lending a reasonable amount of stability for controllers to disconnect and reconnect.

Maybe simply disallowing Gamepad access in third-party iframes would be sufficient? The spec was written with the intent being that only pages that were visible while the user interacted with a gamepad (like pressing a button) should get access to gamepads at all so I don't think this is unreasonable. In that case I think getGamepads() ought to just return an empty array.

I have an existing use case in which this change will render an existing tool useless. https://gamepadviewer.com relies on the fact that a window is not currently focused to display user inputs on-screen for streaming/recording purposes. If the API is inaccessible due do a window not being in focus, this completely destroys the ability for any kind of controller display using the API.

The most typical use case is embedding controllers via Open Broadcaser's browser source component (which is a CEF plugin) but I'm unsure if accessing it via that manner reports to the page that it is currently in focus all the time.