-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
App owned: account linking #335
Conversation
Writing down some thoughts that Brooke and I had late last year, not because I think that should be implemented in this PR, but because I think it could inform the design for the protocol state: When there's more than 2 participants in a websocket channel for device linking, we should track the protocol state for all of them (maybe until a maximum of 10 or 100 or 1000) and simultaneously execute the AWAKE protocol with all of them. (I thought I had written up an issue for that, but I can't find it :/ ) Again, just to inform the design code-wise. I personally find it helpful seeing ways that code might evolve in the future. |
Thanks for bringing it up! Good to think about this now while we are working on this for the app owned version. Do we think we should replace this original pin interaction with this new flow? Or allow for both? I see that @expede opened an issue to discuss AWAKE improvements. I have some questions about how the new flow would work that I'll ask over there. |
I (personally) think we should replace it at some point. But not this PR anyway, so that's a discussion for another day 😄 |
c7cb330
to
764e0c8
Compare
Add onCompletion to producer. The producer implicitly knows it is done after the challenge, but in the future the producer may stay active for multiple account link requests for consumers. The producer onCompletion will be useful then as a signal that all link requests have been handled.
These are the paired functions that developers will implement. delegateAccount returns a record and linkDevice takes a record. It will be up to developers to make sure they the records match.
Returning the username is mostly a convenience for developers, but moving it to the link state might prove useful for multiple accounts at some point in the future. Also, a small change in the consuer to reset the username on reseting the link state. It's not clear yet whether this should also happen in the producer, and in general whether the producer should keep listening after a consumer has been linked.
Instead of expecting callbacks to handle events, the event emitter lets a developer add event listeners. This interface is more flexible for developers and for our internal implementation -- developers can subscribe to events multiple times and we can add events in the future if we want to. At the moment, this is incomplete and we need to handle timeouts and think about cancellation semantics. Various edge cases should also be considered.
The consumer should be informed when linking was declined. A message was added when a proder declines, and an approved field was added to the link event of both the consumer and producer.
We want to avoid module global state because it may modules may be re-instantiated in some cases, which can produce unpleasant and hard to debug situations. This refactor also removes channel and user interaction side effects from many of the account linking functions, which should make them easier to test. Lastly, the dependency injected channel functions are reduced to a single createChannel function. It generates send, receive, and close functions. At the moment, the receive function is unused and maybe won't be needed.
An event is only created when we have at least one listener. This change prevents dispatch for events when no listeners have been added.
The functions are easier to test if they do not depend on the entire linking state. In addition, this will make it easier to re-use them for other AWAKE use cases.
We only want these functions to be called once and only one or the other should be called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super happy with this & the tests! 🎉 Great work.
CI note: we should either increase the timeout or decrease the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I decreased the |
Destructuring the implemenation and exporting its functions does not work because it only happens when the module evaluates. Instead, we can export wrapped versions of the implementation functions.
0142cd5
to
59287f7
Compare
Rename provider to producer and requestor to consumer. Export them at the top level under account instead of auth.
d0d3073
to
95aa96a
Compare
95aa96a
to
2470765
Compare
This is looking good! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bgins here 👋. I took over this feature and submit the PR described below.
Summary
This PR brings the account linking functionality currently in the Fission Auth Lobby into webnative.
This PR implements the following features
console.warn
todebug
moduleResult
type to our collection of common typesThis PR aims to make account linking available to any app that uses webnative. Before this PR, account linking was only available in the Fission Auth Lobby.
API surface
The API exposes account linking providers and requestors. A provider is an authenticated device with the capability to delegate account access. A requestor is an unauthenticated device that would like access.
Note: Internally, we refer to
providers
asproducers
andrequestors
asconsumers
. We rename these in the API with more intuitive names.Follow-up note: We decided to use the names
producer
andconsumer
everywhere. See discussion below.Providers are event emitters with a
cancel
function:A provider immediately listens for account linking requests when created and continues to listen until
cancel
is called. Providers can link multiple requestors without needing to be recreated.Requestors are also event emitters with a
cancel
function:A requestor attempts to link on creation. Unlike providers, requestors are automatically terminated when they complete linking or receive a linking declined message.
Custom account semantics
By default, account linking sets a UCAN that delegates
SUPER_USER
access to the requestor. It expects that the provider is the root user (whose public key matches the DID registered with the server) or has been delegatedSUPER_USER
access by another device with sufficient capabilities.Developers may want to use custom account semantics and they can by dependency injecting three functions:
https://github.com/fission-suite/webnative/blob/98ceb8f5264101481ba44e0bc85f27ed29d7823c/src/auth/implementation/types.ts#L12-L14
checkCapability
checks that a provider can delegate an account for a username whencreateProvider
is called. A provider callsdelegateAccount
to delegate credentials. A consumer callslinkDevice
on receiving a delegation to process and store credentials. These last two functions are tightly coupled --linkDevice
receives whateverdelegateAccount
returns.The default implementation and auth lobby implementation contain examples of these functions.
Account linking always sets the username in storage at
webnative.auth_username
. We rely on a username at this location in other parts of webnative, so we set this internally.Custom channels
By default, account linking uses websockets to send account linking messages between the provider and requestor. Developers may want to use another transport and they can by dependency injecting
createChannel
:https://github.com/fission-suite/webnative/blob/98ceb8f5264101481ba44e0bc85f27ed29d7823c/src/auth/implementation/types.ts#L11
A channel is responsible for sending messages and calling
handleMessage
when messages are received. A channel must be named for the DID associated with the username.https://github.com/fission-suite/webnative/blob/f75f4d22cca84c4437cdf60957971aa37a0f93b6/src/auth/channel.ts#L7-L17
Test plan (required)
Unit tests and prop checks for the provider and requestor are in
producer.test.ts
andconsumer.test.ts
. Individual linking functions are tested, but the interaction between provider and requestor is not.Integration tests to check the interaction between provider and requestor are in
linking.node.test.ts
. This test suite uses an event emitter for its account linking channel. It tracks when providers delegate and requestors link in separate objects. If account linking was successful, the objects should be the same at the end of the test.Closing issues
Closes #305
After Merge
Task list
There were several key pieces: