Skip to content

Conversation

@joshLong145
Copy link

@joshLong145 joshLong145 commented Apr 29, 2024

Description

Adds an authenticate method which will use the authContext if provided to reassign the controllerSessionSigs property on PKPBase which allows for authentication operations to be explicitly invoked. This is helpful when we require to first check the authentication status before allowing other operations to occur. Without this addition it would not be possible to get the controllerSessionSigs before calling a higher level function on PKPEthers for example.
A new validation method has been added validateAuthenticate which will check on the object internally to validate that authentication operations did not fail and we are able to continue with future operations on the network.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

An Additional check has been added to test-pkp-sign-with-session-sigs-session-cache.mjs
to assert that session has been defined before calling signMessage

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
(await this.authContext?.client?.getSessionSigs(
this.authContext.getSessionSigsProps
)) || this.controllerSessionSigs;

Copy link
Collaborator

Choose a reason for hiding this comment

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

can we have an ultimate check to see if controllerSessionSigs exists?

if(!controllerSessionSigs){ throw new Error('bruh.. no session sigs'); }
Copy link
Author

Choose a reason for hiding this comment

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

Updated the pr with a new validation method validateAuthenticate() which will throw if controllerSessionSigs is not defined after authenticate is called.

Copy link
Contributor

@MaximusHaximus MaximusHaximus left a comment

Choose a reason for hiding this comment

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

Questions in-line

const controllerSessionSigs =
(await this.authContext?.client?.getSessionSigs(
this.authContext.getSessionSigsProps
)) || this.controllerSessionSigs;
Copy link
Contributor

Choose a reason for hiding this comment

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

This strikes me as a bit odd -- why would we keep the existing value for this.controllerSessionSigs here rather than throwing an error if our authenticate logic returns a falsy value, or set this.controllerSessionSigs to the falsy value that was returned?

Copy link
Author

Choose a reason for hiding this comment

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

I was also on the fence about this but wanted a fallback if a previous authenticate call was successful. But probably should just let it throw if not defined after getSessionSigs is called.

}
}

public async authenticate(): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to have JSDoc on this if it's part of our public API, especially if we're going to leave the existing controllerSessionSigs intact if our call to getSessionSigs() returns a falsy value, explaining why that is

Copy link
Author

Choose a reason for hiding this comment

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

added doc header

this.throwError('pkpPubKey (aka. uncompressPubKey) is required');
}

this.validateAuthContext();
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we really get rid of this call and assume everything is correct? It seems like we would still want to call it, after calling authenticate? And if we're going to do that, wouldn't we want to leave the logic inside validateAuthContext() intact rather than removing the check for this.controllerSessionSigs?

Copy link
Author

@joshLong145 joshLong145 Apr 29, 2024

Choose a reason for hiding this comment

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

The problem I ran into with the validation was the now both authContext and controllerSessionSigs may be defined on the object since we will assign controllerSessionSigs in scope of authenticate which will fail validation since now both will be defined.

Copy link
Author

Choose a reason for hiding this comment

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

Update: I have added a new validateAuthenticate() method to check on the internal properties of the object after getSessionSigs is called on the client which will perform the needed checks similar to validateAuthContext but is specific to the checks needed after we generate a new session instance.

}
}

public async authenticate(): Promise<void> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

copy/paste this if you need:

 /** * Authenticates the user - generate sessionSigs from litNodeClient(authContext.client) is provided. Otherwise, use * controllerSessionSigs. * * @returns A Promise that resolves to void. * @throws An error if `controllerSessionSigs` is not found. */ 

if (providedAuthentications !== 2) {
// log which authentications has the user provided
if (this.controllerAuthSig) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Contributor

@MaximusHaximus MaximusHaximus left a comment

Choose a reason for hiding this comment

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

Added some questions in-line -- I'm still not sure about what the golden path is for using this API and I think there are some issues w/ error handling. Happy to huddle if you'd like to work it out sync :)

if (this.authContext) {
// It must have a valid client and getSessionSigsProps
if (
!(this.authContext.client instanceof LitNodeClientNodeJs) ||
Copy link
Contributor

Choose a reason for hiding this comment

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

instanceof is less than ideal way to check for validity -- we should avoid it whenever possible, especially given that we're leveraging typescript with interfaces. Consider that if someone passes us something other than a LitNodeClientNodeJs instance, but that thing still conforms to the LitClientSessionManager interface, which the type of this.authMethod expects to see as the client property, then this check will inaccurately throw an error even though it might be a usable implementation.

Also, if we disentangle LitNodeClient from LitNodeClientNodeJs in the future, or define a LitClientSessionManager object that isn't a full fledged LitNodeClientNodeJs instance, then this will be problematic since it might be an instance of multiple implementations of the client.

I think it's safest (and quite reasonable from a usability perspective) just to ducktype check that it appears to be what we expect, using e.g. this.authContext.client && this.authContext.client.getSessionSigsProps

this.controllerSessionSigs,
].filter(Boolean).length;

if (providedAuthentications !== 2) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused -- why is 'any 2' the magic numberof authentications that passes this if check and avoids the throwError() call on L282?

Is it really ok if any combination of two of these is passed in? Why is any 2 OK? A comment here explaining why it's ok if any 2 of 3 are defined, but if only 1 or if all 3 are defined it's a critical error

if (this.authContext) {
const controllerSessionSigs =
await this.authContext?.client?.getSessionSigs(
this.authContext.getSessionSigsProps
Copy link
Contributor

Choose a reason for hiding this comment

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

We try to use this.getSessionSigsProps before we actually validate that it exists inside of validateAuthenticate() (because we don't call it until after we call getSessionSigs() on the client) -- and that means that validateAuthenticate() will never throw an error in this case even if this.getSessionSigsProps is undefined, because calling getSessionSigs() with undefined will cause that function to throw a cannot get property 'sessionKey' of undefined

}
}

private validateAuthenticate() {
Copy link
Contributor

Choose a reason for hiding this comment

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

If we're only going to call it in one place and it's a private method, we may as well just in-line it where it needs to be until and if we need it in multiple places. Incidentally, this relates to my other comment below that we should be validating this.authContext.client and this.getSessionSigsProps before trying to use those properties, since if this wasn't a separate method you could easily validate those 2 things first and the authentications last.

* @throws An error if `controllerSessionSigs` is not found after session generation has resolved.
*/
public async authenticate(): Promise<void> {
// If we dont have an authContext instance then we log that this is being depricated soon in favor of implicit session loading
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is a brand new method, and the only reason I can see that a consumer would ever call it is to run this.authContext.client.getSessionSigs(), can we just make it assume that the authContext functionality must be set, and must work rather than have it fall-through if it's not defined or the client isn't defined?

What is the use case for someone calling this new method without having those things defined, but being OK with the existing this.controllerSessionSigs value still remaining on the object, but only if there are exactly two out of 3 of this.controllerAuthSig, this.authContext and this.controllerSessionSigs defined, even if one of those isn't this.controllerSessionSigs?

@joshLong145
Copy link
Author

Closing as after some investigation with @MaximusHaximus It will be lowering the performance of the overall PKP-* implementations. Will move forward with the Alchemy upgrade with the current implementations using controllerSessionSigs

@joshLong145 joshLong145 closed this May 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants