diff --git a/proposals/4369-capability-error-code.md b/proposals/4369-capability-error-code.md index 6ede91c7c..9c70ea9d3 100644 --- a/proposals/4369-capability-error-code.md +++ b/proposals/4369-capability-error-code.md @@ -20,20 +20,80 @@ Define the following behaviour for existing API endpoints that use capabilities: Capability|Endpoint(s)|Current spec|Proposed behaviour -|-|-|- -[`m.change_password`](https://spec.matrix.org/v1.16/client-server-api/#mchange_password-capability)|[`POST /_matrix/client/v3/account/password`](https://pr2212--matrix-spec-previews.netlify.app/client-server-api/#post_matrixclientv3accountpassword)|Not defined|Return `403` with `M_CAPABILITY_NOT_ENABLED` if `m.change_password`.`enabled` is `false` -[`m.profile_fields`](https://spec.matrix.org/v1.16/client-server-api/#mprofile_fields-capability)|[`PUT /_matrix/client/v3/profile/{userId}/{keyName}`](https://spec.matrix.org/v1.16/client-server-api/#put_matrixclientv3profileuseridkeyname) [`DELETE /_matrix/client/v3/profile/{userId}/{keyName}`](https://spec.matrix.org/v1.16/client-server-api/#delete_matrixclientv3profileuseridkeyname)|`403` for `PUT`. Maybe `403` for `DELETE`. Error code not specified for either|Return `403` with `M_CAPABILITY_NOT_ENABLED` if: `m.profile_fields`.`enabled` is `false`; or, `m.profile_fields`.`disallowed` contains `{keyName}`; -[`m.set_displayname`](https://spec.matrix.org/v1.16/client-server-api/#mset_displayname-capability)|As per `m.profile_fields`|As per `m.profile_fields`|Return `403` with `M_CAPABILITY_NOT_ENABLED` if: `m.profile_fields`.`enabled` is `false`; or, `m.profile_fields`.`disallowed` contains `{keyName}`; or, `m.set_displayname`.`enabled` is `false`; -[`m.set_avatar_url`](https://spec.matrix.org/v1.16/client-server-api/#mset_avatar_url-capability)|As per `m.profile_fields`|As per `m.profile_fields`|Return `403` with `M_CAPABILITY_NOT_ENABLED` if: `m.profile_fields`.`enabled` is `false`; or, `m.profile_fields`.`disallowed` contains `{keyName}`; or, `m.set_avatar_url`.`enabled` is `false`; -[`m.3pid_changes`](https://spec.matrix.org/v1.16/client-server-api/#m3pid_changes-capability)|[`POST /_matrix/client/v3/account/3pid`](https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3account3pid) [`POST /_matrix/client/v3/account/3pid/add`](https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3account3pidadd) [`POST /_matrix/client/v3/account/3pid/delete`](https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3account3piddelete)|Not defined|Return `400` with `M_CAPABILITY_NOT_ENABLED` if `m.3pid_changes`.`enabled` is `false` -[`m.get_login_token`](https://spec.matrix.org/v1.16/client-server-api/#mget_login_token-capability)|[`POST /_matrix/client/v1/login/get_token`](https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv1loginget_token)|Maybe `400` with undefined error code if `m.get_login_token`.`enabled` is `false`|`403` with `M_CAPABILITY_NOT_ENABLED` if `m.get_login_token`.`enabled` is `false` +[`m.change_password`]|[`POST /_matrix/client/v3/account/password`]|Not defined|Return `403` with `M_CAPABILITY_NOT_ENABLED` if `m.change_password`.`enabled` is `false` +[`m.profile_fields`]|[`PUT /_matrix/client/v3/profile/{userId}/{keyName}`] [`DELETE /_matrix/client/v3/profile/{userId}/{keyName}`]|`403` for `PUT`. Maybe `403` for `DELETE`. Error code not specified for either|Return `403` with `M_CAPABILITY_NOT_ENABLED` if: `m.profile_fields`.`enabled` is `false`; or, `m.profile_fields`.`disallowed` contains `{keyName}`; +[`m.set_displayname`]|As per `m.profile_fields`|As per `m.profile_fields`|Return `403` with `M_CAPABILITY_NOT_ENABLED` if: `m.profile_fields`.`enabled` is `false`; or, `m.profile_fields`.`disallowed` contains `{keyName}`; or, `m.set_displayname`.`enabled` is `false`; +[`m.set_avatar_url`]|As per `m.profile_fields`|As per `m.profile_fields`|Return `403` with `M_CAPABILITY_NOT_ENABLED` if: `m.profile_fields`.`enabled` is `false`; or, `m.profile_fields`.`disallowed` contains `{keyName}`; or, `m.set_avatar_url`.`enabled` is `false`; +[`m.3pid_changes`]|[`POST /_matrix/client/v3/account/3pid`] [`POST /_matrix/client/v3/account/3pid/add`] [`POST /_matrix/client/v3/account/3pid/delete`]|Not defined|Return `403` with `M_CAPABILITY_NOT_ENABLED` if `m.3pid_changes`.`enabled` is `false` +[`m.get_login_token`]|[`POST /_matrix/client/v1/login/get_token`]|Maybe `400` with undefined error code if `m.get_login_token`.`enabled` is `false`|`403` with `M_CAPABILITY_NOT_ENABLED` if `m.get_login_token`.`enabled` is `false` ## Potential issues -TODO: Change in behaviour on `m.get_login_token`. +### Possible change in behaviour on `m.get_login_token` + +The spec for [`POST /_matrix/client/v1/login/get_token`] says: + +> **Status** 400 +> The request was malformed, or the user does not have an ability to generate tokens for their devices, as implied by +> the User-Interactive Authentication API. +> Clients should verify whether the user has an ability to call this endpoint with the m.get_login_token capability. + +So, it doesn't explicitly say that `400` is the expected response if the capability is not available to the user. But, +it might imply it and it is possible that some implementations might rely on this. + +However, a mitigation is that since [`POST /_matrix/client/v1/login/get_token`] was introduced by [MSC3882] it has +always had a capability associated with it and so clients should know to check the capability in advance. + +### Changes from implementations in the wild + +Endpoint(s)|Synapse current +-|- +[`POST /_matrix/client/v3/account/password`]|`403` with `M_FORBIDDEN` +[`PUT /_matrix/client/v3/profile/{userId}/{keyName}`] [`DELETE /_matrix/client/v3/profile/{userId}/{keyName}`]|`400` with `M_FORBIDDEN` +[`POST /_matrix/client/v3/account/3pid`] [`POST /_matrix/client/v3/account/3pid/add`] [`POST /_matrix/client/v3/account/3pid/delete`]|`400` with `M_FORBIDDEN` +[`POST /_matrix/client/v1/login/get_token`]|`404` with `M_UNRECOGNIZED` ## Alternatives -Base on existing implementations. This is what was originally in https://github.com/matrix-org/matrix-spec/pull/2212 +### Codify existing Synapse behaviour + +We could simply codify what is in the existing Synapse implementation (see above). This is what was originally proposed +in https://github.com/matrix-org/matrix-spec/pull/2212. + +However, that doesn't consider non-Synapse implementations. + +### Increment version on affected endpoints + +Deprecate the old version and introduce a new version with the updated error responses. + +e.g. +`POST /_matrix/client/`**`v3`**`/account/password` would be deprecated and continue to return `403` with `M_FORBIDDEN` and +`POST /_matrix/client/`**`v4`**`/account/password` would return `403` with `M_CAPABILITY_NOT_ENABLED` + +### Allow client to specify versions + +Perhaps this has been discussed elsewhere previously, but clients could specify a spec version alongside each request +(perhaps in an HTTP header) and the server used that to determine what error code to return. + +e.g. + +```http +POST /_matrix/client/v3/account/password +Host: example.com +Matrix-Version: v1.16 +``` + +Would return `403` with `M_FORBIDDEN`. But if a later version specified then the new error code is given: + +```http +POST /_matrix/client/v3/account/password +Host: example.com +Matrix-Version: v1.17 +``` + +Could return `403` with `M_CAPABILITY_NOT_ENABLED`. + +That way clients effectively opt-in to the change in format. ## Security considerations @@ -41,7 +101,7 @@ None. ## Unstable prefix -Whilst this proposal is under development the `IO.ELEMENT.MSCXXXX_CAPABILITY_NOT_ENABLED` value +Whilst this proposal is under development the `IO.ELEMENT.MSC4369_CAPABILITY_NOT_ENABLED` value should be used instead of `CAPABILITY_NOT_ENABLED`. ## Dependencies @@ -51,3 +111,17 @@ None. [capabilities negotiation]: https://spec.matrix.org/v1.16/client-server-api/#capabilities-negotiation [Client-Server API]: https://spec.matrix.org/v1.16/client-server-api/ [other error code]: https://spec.matrix.org/v1.16/client-server-api/#other-error-codes +[MSC3882]: https://github.com/matrix-org/matrix-spec-proposals/pull/3882 +[`m.change_password`]: https://spec.matrix.org/v1.16/client-server-api/#mchange_password-capability +[`m.profile_fields`]: https://spec.matrix.org/v1.16/client-server-api/#mprofile_fields-capability +[`m.set_displayname`]: https://spec.matrix.org/v1.16/client-server-api/#mset_displayname-capability +[`m.set_avatar_url`]: https://spec.matrix.org/v1.16/client-server-api/#mset_avatar_url-capability +[`m.3pid_changes`]: https://spec.matrix.org/v1.16/client-server-api/#m3pid_changes-capability +[`m.get_login_token`]: https://spec.matrix.org/v1.16/client-server-api/#mget_login_token-capability +[`POST /_matrix/client/v3/account/password`]: https://pr2212--matrix-spec-previews.netlify.app/client-server-api/#post_matrixclientv3accountpassword +[`PUT /_matrix/client/v3/profile/{userId}/{keyName}`]: https://spec.matrix.org/v1.16/client-server-api/#put_matrixclientv3profileuseridkeyname +[`DELETE /_matrix/client/v3/profile/{userId}/{keyName}`]: https://spec.matrix.org/v1.16/client-server-api/#delete_matrixclientv3profileuseridkeyname +[`POST /_matrix/client/v3/account/3pid`]: https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3account3pid +[`POST /_matrix/client/v3/account/3pid/add`]: https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3account3pidadd +[`POST /_matrix/client/v3/account/3pid/delete`]: https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3account3piddelete +[`POST /_matrix/client/v1/login/get_token`]: https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv1loginget_token