Page MenuHomePhabricator

[Keyserver] Attempt login to identity service
ClosedPublic

Authored by jon on Jun 30 2023, 4:05 PM.
Tags
None
Referenced Files
Unknown Object (File)
Tue, May 7, 10:11 PM
Unknown Object (File)
Tue, May 7, 6:29 PM
Unknown Object (File)
Sat, May 4, 11:13 PM
Unknown Object (File)
Sat, May 4, 11:13 PM
Unknown Object (File)
Sat, May 4, 11:12 PM
Unknown Object (File)
Sat, May 4, 11:12 PM
Unknown Object (File)
Sat, May 4, 11:12 PM
Unknown Object (File)
Sat, May 4, 11:12 PM
Subscribers

Details

Summary

Have keyserver attempt to login with identity service
at start up. Save userId and access token.

Part of https://linear.app/comm/issue/ENG-3978

Depends on D8404

Test Plan
# start docker
# start localstack
comm-dev services start

# start identity service
(cd services/identity && RUST_LOG=debug cargo run -- server &)

# start keyserver
cd keyserver && yarn dev

# assert user was written to database
awslocal dynamodb scan --table-name identity-users

# assert that credentials were written to keyserver's metadata table

Diff Detail

Repository
rCOMM Comm
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Harbormaster returned this revision to the author for changes because remote builds failed.Jun 30 2023, 4:19 PM
Harbormaster failed remote builds in B20665: Diff 28321!
jon added inline comments.
keyserver/src/user/login.js
30 ↗(On Diff #28321)

not really sure the best way to coerce mixed into string here. But that's why flow is failing

41–44 ↗(On Diff #28321)

I just need to get the first value, but not sure the best way to do so

147–152 ↗(On Diff #28321)

one thing to note, is that marcin's work in keys-responder also marks the prekey and one time keys as published, introducing a potential race condition. This shouldn't really be much of an issue as this is executed on start up, and his work will wait for a request.

I also plan on removing the outgoing-message work in https://linear.app/comm/issue/ENG-4290

ashoat requested changes to this revision.Jul 3 2023, 11:52 AM
ashoat added inline comments.
keyserver/src/user/login.js
30 ↗(On Diff #28321)

Object.values has a bug in Flow. This bug is fixed in Flow 0.196.0, but we're still on 0.182.0. The Flow update is blocked on the next React Native upgrade, which should happen in the coming months (hopefully)

For now, we work around this with a values utility in lib/utils/objects.js, which uses $FlowFixMe (basically an any-cast) to silence the error

39 ↗(On Diff #28321)

validateAccountPrekey appears to be an async function. From my review of D8400:

This is actually very risky because if it throws an exception, nothing will catch it. The issue is that if the promise rejects without being caught, Node.js treats this a bit like an exception being thrown and not caught. You'll see an "unhandled promise rejection" warning in our current version of Node. But in more recent versions of Node, this would crash the whole app.

In other words, in Node.js code we should never call a function that returns a Promise (such as an async function) WITHOUT either awaiting it OR wrapping it in handleAsyncPromise.

In this case, however, it doesn't appear that there is any good reason for validateAccountPrekey to be an async function, as it does not use the await keyword. As such, we should probably just turn validateAccountPrekey into a normal function.

It looks like it would introduce a Flow error currently to do that, but that should be solvable by updating fetchCallUpdateOlmAccount so that it accepts any callback that returns T | Promise<T> (rather than requiring Promise<T>).

41–44 ↗(On Diff #28321)

Here's what I would suggest:

const [prekey] = Object.values(prekeyMap);

You might need to use the aforementioned values utility if you see Flow errors.

90 ↗(On Diff #28321)

I think this name is more clear. Your original name seems like it's validating a login action, or the result of a login action

93–99 ↗(On Diff #28321)

Always early exit please. Simple case should go first to reduce mental RAM

114–152 ↗(On Diff #28321)

This appears to be copy-pasted from getOlmSessionInitializationDataResponder. Instead of copy-pasting, ideally we could factor out the shared code.

If it's possible to factor out, can you please introduce a preceding diff to this one that does it? If not, can you explain why it can't be factored out?

one thing to note, is that marcin's work in keys-responder also marks the prekey and one time keys as published, introducing a potential race condition.

Can you explain the race condition in a bit more detail? fetchCallUpdateOlmAccount should prevent races

168–169 ↗(On Diff #28321)

You should never leave a dangling Promise like this in Node.js code. You should either await it or wrap in handleAsyncPromise. See comment above for more details

186–187 ↗(On Diff #28321)

You should never leave a dangling Promise like this in Node.js code. You should either await it or wrap in handleAsyncPromise. See comment above for more details

This revision now requires changes to proceed.Jul 3 2023, 11:52 AM
jon marked 8 inline comments as done.

Address feedback

ashoat requested changes to this revision.Jul 6 2023, 1:05 PM

Concerned that you're still not understanding the feedback, even after I spent a lot of time in my last review typing it out thoughtfully. Please try to make sure you grok the feedback being updating this diff again. If you're not sure that you understand the feedback, I would much rather you message me about it then to update this diff again without addressing the feedback

keyserver/src/user/login.js
39 ↗(On Diff #28321)

From my last review:

it doesn't appear that there is any good reason for validateAccountPrekey to be an async function

You appear to have made some related changes, but validateAccountPrekey is still an async function. Can you make it a normal function?

114–152 ↗(On Diff #28321)

Not sure this was responded to?

168–169 ↗(On Diff #28321)

You didn't actually address the feedback – promise is still dangling.

Please try "digging deeper" in understanding promises / async / await. It feels like you're currently taking a "guess and check" approach. You should make sure you actually understand this stuff...

Please re-review my feedback, and potentially look for some resources online to augment your understanding of things like Promise.all, the "unhandled promise rejection" error from Node, etc.

186–187 ↗(On Diff #28321)

Same here

This revision now requires changes to proceed.Jul 6 2023, 1:05 PM
jon marked 4 inline comments as done.

Address feedback

keyserver/src/user/login.js
30 ↗(On Diff #28321)

For now, we work around this with a values utility in lib/utils/objects.js

Thanks

39 ↗(On Diff #28321)

It looks like it would introduce a Flow error currently to do that, but that should be solvable by updating fetchCallUpdateOlmAccount so that it accepts any callback that returns T | Promise<T> (rather than requiring Promise<T>).

Ah, that was my issue. I made it not async, but ran into flow issues, then did a partial revert.

Allowed for T in fetchCallUpdateOlmAccount. Then updated the two functions in question

39 ↗(On Diff #28321)

yea, thought I made those changes.

41–44 ↗(On Diff #28321)

yea, was tired of the flow errors.

Thanks

90 ↗(On Diff #28321)

Sounds good. Was going more the "pake login state" (noun), but loggedIn is probably more readable.

114–152 ↗(On Diff #28321)

It can be factored, but the code overlap should be removed in https://linear.app/comm/issue/ENG-4290/replace-usage-of-keyserver-x3dh-endpoint-with-identity-service.

Since it uses scoping to introduce quite a few items, the refactored method would be quite a doozy. But maybe it's worthwhile to refactor it.

Can you explain the race condition in a bit more detail? fetchCallUpdateOlmAccount should prevent races

Between lines 152 and 168 (or 186), it might be possible for someone to request the outgoing X3DH key details from the keys-responder. In which case the endpoint will return 11 one-time-keys, and then immediately mark them all as published.

Then when execution comes back to login.js, the following lines willl have already occurred:

fetchCallUpdateOlmAccount('content', markKeysAsPublished);
fetchCallUpdateOlmAccount('notifications', markKeysAsPublished);
114–152 ↗(On Diff #28321)

Never submitted, sorry.

168–169 ↗(On Diff #28321)

used Promise.all

168–169 ↗(On Diff #28321)

I'm used to rust giving me a warning about "un-awaited" promises. Added awaits to Promise.all usages

ashoat requested changes to this revision.Jul 11 2023, 3:31 PM

Close!

keyserver/src/keyserver.js
70 ↗(On Diff #28593)

I think we decided to move this to happen before the fork, in order to avoid races with the retrieveAccountKeysSet in keyserver/src/responders/keys-responders.js

keyserver/src/user/login.js
17 ↗(On Diff #28593)

Nit

44 ↗(On Diff #28593)

See here. How about invalid_prekey?

66 ↗(On Diff #28593)

Delete trailing semicolon

69 ↗(On Diff #28593)

Nit

76 ↗(On Diff #28593)

There's no await keyword, so this should not be an async function. You're creating a new Promise unnecessarily

143–150 ↗(On Diff #28593)

Combine these awaits with Promise.all

170 ↗(On Diff #28593)

Let's get rid of this console.log. It's unnecessarily "scary" for a first-time registration, where it's unexpected

187 ↗(On Diff #28593)

Let's get rid of this console.log

190 ↗(On Diff #28593)

When you concatenate these, you're assuming err is a string or can be coerced into one. We shouldn't make that assumption

Also better to use console.warn

191 ↗(On Diff #28593)
  1. See here. How about identity_auth_failed?
  2. Why do you use ServerError above, but Error here?
114–152 ↗(On Diff #28321)

It can be factored, but the code overlap should be removed in https://linear.app/comm/issue/ENG-4290/replace-usage-of-keyserver-x3dh-endpoint-with-identity-service.

Since it uses scoping to introduce quite a few items, the refactored method would be quite a doozy. But maybe it's worthwhile to refactor it.

Fair enough, that makes sense to me

Between lines 152 and 168 (or 186), it might be possible for someone to request the outgoing X3DH key details from the keys-responder. In which case the endpoint will return 11 one-time-keys, and then immediately mark them all as published.

In our 1:1, we decided to address this by awaiting verifyUserLoggedIn before we fork Express servers

This revision now requires changes to proceed.Jul 11 2023, 3:31 PM
jon marked 12 inline comments as done.

Address feedback

keyserver/src/user/login.js
17 ↗(On Diff #28593)

Unfortunately this needs to agree with the rust bindings. userId -> user_id, however, userID becomes user_i_d; which is really weird. Structs defined in rust seem to be able to allow renaming in JS, but I don't see anything similar for JS to rust.

@varun , do you know a solution?

69 ↗(On Diff #28593)

see above, this makes the rust binding user_i_d, which is odd

76 ↗(On Diff #28593)

thanks

170 ↗(On Diff #28593)

Yea, it was useful for debugging. I'll get rid of it.

191 ↗(On Diff #28593)

Why do you use ServerError above, but Error here?

Was probably writting rust before doing this line, and forgot about ServerError

keyserver/src/user/login.js
17 ↗(On Diff #28593)

sorry, don't know a solution :(

Please remove the async declaration from saveIdentityInfo

keyserver/src/user/login.js
17 ↗(On Diff #28593)

Thanks for explaining... it's just a nit, I don't feel strongly. Let's just keep it as-is

76 ↗(On Diff #28593)

This wasn't addressed

This revision is now accepted and ready to land.Jul 13 2023, 10:28 AM
jon marked an inline comment as done.

remove extra async keyword

This revision was landed with ongoing or failed builds.Jul 16 2023, 7:39 PM
This revision was automatically updated to reflect the committed changes.