Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Add 3pid unbind callback to module API #13227

Closed
wants to merge 7 commits into from
Closed

Conversation

MatMaul
Copy link
Contributor

@MatMaul MatMaul commented Jul 8, 2022

Currently we have a module interface that can react on a 3pid bind action, but it doesn't exist for unbind.

We rely on the fact that the identity server where we want to unbind should be stored in user_threepid_id_server table.
Unfortunately the info there doesn't include the scheme, hence a bind to http://localhost:7777 will fail on unbind because https://localhost:7777 is called instead.

To overcome that this PR introduces a similar callback for 3pid unbind, so we can also override the identity server URL there for example.

@MatMaul MatMaul requested a review from a team as a code owner July 8, 2022 14:57
@babolivier babolivier added the Z-Time-Tracked Element employees should track their time spent on this issue/PR. label Jul 8, 2022
@squahtx squahtx marked this pull request as draft July 11, 2022 11:17
@MatMaul MatMaul force-pushed the mv/unbind-callback branch 8 times, most recently from 6e8db1e to 6cd2726 Compare July 12, 2022 15:28
@babolivier babolivier requested review from babolivier and removed request for a team July 12, 2022 15:32
@MatMaul MatMaul force-pushed the mv/unbind-callback branch 6 times, most recently from 381e73e to 89ef487 Compare July 12, 2022 21:22
@MatMaul MatMaul changed the title [Draft] Add 3pid unbind callback to module API Add 3pid unbind callback to module API Jul 12, 2022
@MatMaul MatMaul marked this pull request as ready for review July 12, 2022 21:35
@MatMaul
Copy link
Contributor Author

MatMaul commented Jul 12, 2022

This is now tested alongside matrix-org/synapse-bind-sydent#2, and tests seems to pass outside of an unrelated (flaky ?) one I think.

@MatMaul MatMaul force-pushed the mv/unbind-callback branch from 89ef487 to 0951ff7 Compare July 18, 2022 09:25
docs/modules/third_party_rules_callbacks.md Outdated Show resolved Hide resolved
changelog.d/13227.feature Outdated Show resolved Hide resolved
synapse/events/third_party_rules.py Outdated Show resolved Hide resolved
synapse/events/third_party_rules.py Outdated Show resolved Hide resolved
docs/modules/third_party_rules_callbacks.md Outdated Show resolved Hide resolved
synapse/events/third_party_rules.py Outdated Show resolved Hide resolved
docs/modules/third_party_rules_callbacks.md Outdated Show resolved Hide resolved
MatMaul and others added 3 commits August 3, 2022 14:52
@MatMaul MatMaul force-pushed the mv/unbind-callback branch from 9ad1153 to 9b4c0e7 Compare August 3, 2022 14:26
@MatMaul MatMaul requested a review from babolivier August 9, 2022 16:01
Copy link
Contributor

@babolivier babolivier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about the delay on this one!

docs/modules/third_party_rules_callbacks.md Outdated Show resolved Hide resolved
Copy link
Contributor

@babolivier babolivier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly changes for documentation (but also a bit about the logic around the return value). I haven't looked at the test yet, since I assume it might change as a result of discussions around some of the comments I've made.

A module can hence do its own custom unbinding, if for example it did also registered a custom
binding logic with `on_threepid_bind`.

It should return a tuple of 2 booleans:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It should return a tuple of 2 booleans:
The module must return a tuple of 2 booleans, which indicate respectively:

The main thing here is replacing "should" by "must": "should" implies the module is strongly encouraged to do something but there isn't a strict obligation. "must" implies there's a strict obligation, rather than a strong encouragement (which is the case here - Synapse won't be able to process any other type of return value).

) -> Tuple[bool, bool]:
```

Called before a threepid association is removed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Called before a threepid association is removed.
Called before the association between a local user and a third-party identifier
(email address, phone number) is removed.

I wouldn't expect users who aren't deeply familiar with Matrix's concepts to know what a "threepid" is.

as well as the medium (`email` or `msisdn`), address of the third-party identifier and
the identity server where the threepid was successfully registered.

A module can hence do its own custom unbinding, if for example it did also registered a custom
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A module can hence do its own custom unbinding, if for example it did also registered a custom
A module can hence implement its own custom unbinding, if for example it also implemented a custom

(changed, stop) = await callback(
user_id, medium, address, identity_server
)
global_changed |= changed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we rather indicate whether all callbacks succeeded, rather than just one of them?

Comment on lines +288 to +293
- first one should be `True` on a success calling the identity server, otherwise `False` if
the identity server doesn't support unbinding (or no identity server found to contact).
- second one should be `True` if unbind needs to stop there. In this case no other module
unbind will be called, and the default unbind made to the IS that was used on bind will also be
skipped. In any case the mapping will be removed from the Synapse 3pid remote table,
except if an Exception was raised at some point.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- first one should be `True` on a success calling the identity server, otherwise `False` if
the identity server doesn't support unbinding (or no identity server found to contact).
- second one should be `True` if unbind needs to stop there. In this case no other module
unbind will be called, and the default unbind made to the IS that was used on bind will also be
skipped. In any case the mapping will be removed from the Synapse 3pid remote table,
except if an Exception was raised at some point.
- whether the unbind was successful (`True` in this case, `False` otherwise).
- whether Synapse should stop the unbinding process there (`True` in this case, `False` otherwise). In
this case, Synapse will also remove any local record of an association between the local user and the
third-party identifier on a remote identity server.
If multiple modules implement this callback, they will be considered in order. Unless the return value of
a callback indicates to stop the unbinding process, Synapse falls through to the next one. Otherwise,
Synapse will not call any subsequent implementation of this callback.

We should also add to the last paragraph a mention of how the first boolean is processed once we have resolved this question in a previous thread.

A few things this suggestion changes:

  • I don't believe it is safe to assume all modules will do their binding/unbinding against an identity server, so it might not make sense to tie the definition of return values to the existence of an identity server.
  • The bit about exceptions don't feel right to me: first, looking at the code it doesn't look correct; second the way it's phrased makes it sound like modules should use exceptions to define whether Synapse should delete the remote record, and using exceptions as a control method is something we actively try to discourage.
  • Also some clarity and consistency on how Synapse handles multiple modules implementing this callback.

url_bytes=url_bytes,
content=content,
destination_is=id_server.encode("ascii"),
(changed, stop,) = await self.hs.get_third_party_event_rules().unbind_threepid(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(changed, stop,) = await self.hs.get_third_party_event_rules().unbind_threepid(
changed, stop = await self.hs.get_third_party_event_rules().unbind_threepid(

await self.blacklisting_http_client.post_json_get_json(
url, content, headers
# If a module wants to take over unbind it will return stop = True,
# in this case we should just purge the table from the 3pid record
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# in this case we should just purge the table from the 3pid record
# in this case we should just remove the entry from the 3pid remote records table

Comment on lines +538 to +539
Note that this callback is called before an association is deleted on the
local homeserver.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels a bit superfluous with the line above?

Comment on lines +548 to +552
A tuple of 2 booleans reporting if a changed happened for the first, and if unbind
needs to stop there for the second (True value). In this case no other module unbind will be
called, and the default unbind made to the IS that was used on bind will also be skipped.
In any case the mapping will be removed from the Synapse 3pid remote table, except if an Exception
was raised at some point.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A tuple of 2 booleans reporting if a changed happened for the first, and if unbind
needs to stop there for the second (True value). In this case no other module unbind will be
called, and the default unbind made to the IS that was used on bind will also be skipped.
In any case the mapping will be removed from the Synapse 3pid remote table, except if an Exception
was raised at some point.
A tuple of 2 booleans reporting, respectively, if the unbind was successful, and if the unbind process
should stop there.

The bit about what happens if the second bool is True is only relevant to module callbacks, not to the interface.

@anoadragon453
Copy link
Member

Currently we have a module interface that can react on a 3pid bind action, but it doesn't exist for unbind.

Not quite I'm afraid. Currently we have a on_threepid_bind method which has nothing to do with identity servers association bindings. It is called when a local association is made on the homeserver. The method proposed in this PR would only be tangentially related to the existing method (and it would be confusing if they were given similar names). I've outlined this problem in more detail at #14955.

Additionally in the same issue, I've tweaked the design of the module callback method proposed by this PR: #14955 (comment). The tweaked design only returns a single boolean while still fitting the use case of synapse-bind-sydent.

@anoadragon453
Copy link
Member

This PR has been superseded by #15044.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Z-Time-Tracked Element employees should track their time spent on this issue/PR.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants