deltachat / mailadm

mail account administration tool for temporary and other account creation/modification
https://mailadm.readthedocs.io/
Mozilla Public License 2.0
14 stars 1 forks source link

Make `new_email` POST request handler idempotent #102

Open link2xt opened 1 year ago

link2xt commented 1 year ago

Currently if POST request succeeds, but connection fails before the client receives a response, an account is created but nobody will use it. In extreme case of one-use token (#89), this will result in making token unusable without creating an account on user device.

If the request was idempotent, user device could resend a POST request again and receive a password.

Currently the only parameter is t, the token. I propose to add another optional (for backwards compatibility) parameter, lets name it i, which contains a random string (token) generated by the client. If specified, it should be used to deterministically generate an username and a password, e.g. username = hash("username" + token + salt + i parameter), password = hash("password" + token + salt + i parameter). If mailbox already exists, return the response as if it was just successfully created, without even checking if the password is still the same.

Delta Chat will then be able to generate i parameter locally, save it in the context config and make as many POST requests as needed to actually get login + password and configure an account, even on a bad connection.

hpk42 commented 1 year ago

On Sat, Jan 28, 2023 at 17:10 -0800, link2xt wrote:

Currently if POST request succeeds, but connection fails before the client receives a response, an account is created but nobody will use it. In extreme case of one-use token (#89), this will result in making token unusable without creating an account on user device.

If the request was idempotent, user device could resend a POST request again and receive a password.

Currently the only parameter is t, the token. I propose to add another optional (for backwards compatibility) parameter, lets name it i, which contains a random string (token) generated by the client. If specified, it should be used to deterministically generate an username and a password, e.g. username = hash("username" + token + salt + i parameter), password = hash("password" + token + salt + i parameter). If mailbox already exists, return the response as if it was just successfully created, without even checking if the password is still the same.

Delta Chat will then be able to generate i parameter locally, save it in the context config and make as many POST requests as needed to actually get login + password and configure an account, even on a bad connection.

How is an unused row in a database a problem? Idempotency here adds complexity on both mailadm and DC-side just to avoid an empty unused account .... which should be pruned/expired anyway if nobody ever logged in for some weeks and send or received a message.

link2xt commented 1 year ago

How is an unused row in a database a problem?

The problem is that the number of accounts is increased, in case of one-time tokens it will hit max-use limit without anyone getting an account.

Without i parameter it is impossible to implement retries and user may not get an account at all on bad connection, while the token will be considered used. The only solution without changing the client side is to pre-generate the password, but then multiple users can scan the same QR code twice and get the same account.

link2xt commented 1 year ago

The standard way is to have an Idempotency-Key header and some in-memory cache (usually Redis, but in our case it's an overkill I guess, a python dictionary is sufficient) on the server side, to cache responses for some time if request had a key set.

There is a standard draft for this at https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/ and it is already implemented by APIs like https://stripe.com/docs/api/idempotent_requests

With this implemented, Delta Chat could retry the same request for minutes or hours until it succeeds. If user is connected to some bad network when scanning QR code, they can then switch to another network and still get an account without having to rescan the QR code.

link2xt commented 11 months ago

Made a PR: #131