Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Trying to help you with debugging AUTH on master branch #246

Open
jeremyd opened this issue Jun 27, 2024 · 10 comments
Open

Trying to help you with debugging AUTH on master branch #246

jeremyd opened this issue Jun 27, 2024 · 10 comments

Comments

@jeremyd
Copy link
Contributor

jeremyd commented Jun 27, 2024

I see you made some changes to "fix AUTH", but for my example, AUTH is broken both on the release, and on master branch. Here is a rough example code of the basics of what I'm attempting here:

// Top level constants
const nip07signer = new NDKNip07Signer();

const ndk = new NDK({
    signer: nip07signer,
    autoConnectUserRelays: false,
    enableOutboxModel: false,
});

// inside UseEffect
const ndkPool = ndk.pool;
            ndkPool.on("flapping", (flapping: NDKRelay) => {
                addToStatus("relay is flapping: " + flapping.url);
            });
            ndkPool.on("relay:auth", (relay: NDKRelay, challenge: string) => {
                addToStatus("auth: " + relay.url);
            });
            ndkPool.on("relay:authed", (relay: NDKRelay) => {
                addToStatus("authed: " + relay.url);
                const kind1Sub = ndk.subscribe({ kinds: [1], limit: relayLimit }, {closeOnEose: false});
                kind1Sub.on("event", (event: NDKEvent) => {
                    if(lookupProfileName(event.pubkey) == event.pubkey) {
                        const profileSub = ndk.subscribe({ kinds: [0], limit: 1, authors: [event.pubkey] }, {closeOnEose: true});
                        profileSub.on("event", (pevent: NDKEvent) => {
                            addProfile(pevent);
                        });
                    }
                    addPost(event);
                });
            });
            ndkPool.on("relay:disconnect", (relay: NDKRelay) => {
                addToStatus("disconnected: " + relay.url);
            });

            ndkPool.on("relay:connect", (relay: NDKRelay) => {
                addToStatus("connect: " + relay.url);
                
            });

            ndkPool.on("relay:connecting", (relay: NDKRelay) => {
                addToStatus("connecting: " + relay.url);
            });

            ndk.addExplicitRelay(nrelaydata, NDKRelayAuthPolicies.signIn({ndk}), true);

So, here's what I found:

First of all, just want to mention that the following did NOT work, although it seems like it should have. Having the two different policies (one for the pool and one per relay) may just not apply to explicit relays or etc, I don't know but the if statement to select either or, is not working apparently:

ndk.relayAuthDefaultPolicy = NDKRelayAuthPolicies.signIn({ndk});
ndk.addExplicitRelay(nrelaydata);
await ndk.connect();

However, after some digging I managed to get farther by passing a policy and connect=true to addExplicitRelay.

Second of all, the nitty gritty debug. AUTH was still not working, I could see the auth message come through on the relay but the relay itself inside NDK is stuck in "connect" (ie, it connected then doesn't proceed). Here's why:

On line 82 of connectivity.ts this if statement was returning false when it should be true. res when inspected, is not a bool, it is an object. I naievely hotwired this to if (!!res === true) and this got farther down the code path. At this point, the signed event had already arrived at the relay and should be clear to proceed.

The next error happens on line 83 of connectivity.ts it fails saying "No signer available for authentication". This is not the case, it has already signed the AUTH event and sent it off to the relay at this point so clearly it has a signer. This is NIP07 signer. So I hotwired this as well by commenting it out and jumping straight to the if statement on line 85 of connectivity.ts changing it from an else to an if (this._status === NDKRelayStatus.AUTHENTICATING) which returns true.

This allowed NDK to continue and 💥 my code started working. I am receiving reqs, and the pool is now emiting all the statuses I expected to see and subscribing etc.

I hope this helps you figure out what mistakes are happening here! My hot-wiring is obviously not PR ready or anything as I still need to understand more about some of this. I have a feeling that bunkers vs. nip07 and possibly just some bad if's are the culprit here.

@jeremyd
Copy link
Contributor Author

jeremyd commented Jun 27, 2024

could be that we're not setting the NDK here when addExplicitRelay is called:

ndk/src/ndk/index.ts line 327

  •        relay = new NDKRelay(urlOrRelay, relayAuthPolicy);
    
  •                   relay = new NDKRelay(urlOrRelay, relayAuthPolicy, this);
    

@jeremyd
Copy link
Contributor Author

jeremyd commented Jun 27, 2024

Ok, I think I am starting to understand what's going on here. (Or at least guess..)

It appears to me that the first part of the auth handler was meant for NIP07 use.. and it's simply not setting the status to connected and emitting auth. So when i back out my hotwiring, and just add these things, I think this is working also and that the second part of the authHandler, where it asks if res===true, that must be for bunker signing.

@jeremyd
Copy link
Contributor Author

jeremyd commented Jun 27, 2024

Like this:

                    if (res instanceof NDKEvent) {
                        this.relay.auth(async (evt: EventTemplate): Promise<VerifiedEvent> => {
                            return res.rawEvent() as VerifiedEvent;
                        });
                            this._status = NDKRelayStatus.CONNECTED;
                            this.ndkRelay.emit("authed");
                    }

@jeremyd
Copy link
Contributor Author

jeremyd commented Jun 29, 2024

Turns out I was just confused about all this stuff. I have backed out all my changes to NDK, and things are working. I even went back to latest released version 2.8.2 and it's also working. I learned a LOT about the internals of NDK, so that's a win. I am enjoying these grouped subscriptions and auth features. Thank you.

Here's some example code of what finally seems like a pattern that works for me. I have to delay the subscription until after the auth for it to work. I also have to make sure to close the subscription on disconnect and re-create it. Overall, I'm very happy with this now. PV

const nip07signer = new NDKNip07Signer();

const ndk = new NDK({
    signer: nip07signer,
    autoConnectUserRelays: false,
    enableOutboxModel: false,
});

const ndkPool = ndk.pool;

export default function PostsPage() {

async function grabStuff(nrelaydata: string, auth: boolean = false) {
        var kind1Sub: NDKSubscription
        
        ndkPool.on("flapping", (flapping: NDKRelay) => {
            addToStatus("relay is flapping: " + flapping.url);
        });
        ndkPool.on("relay:auth", (relay: NDKRelay, challenge: string) => {
            addToStatus("auth: " + relay.url);
        });

        ndkPool.on("relay:authed", (relay: NDKRelay) => {
            addToStatus("authed: " + relay.url);
            wipePosts();
            kind1Sub = ndk.subscribe({ kinds: [1], limit: relayLimit }, {closeOnEose: false, groupable: false});
            kind1Sub.on("event", (event: NDKEvent) => {
                // do profile lookups on the fly
                if(lookupProfileName(event.pubkey) == event.pubkey) {
                    const profileSubAuth = ndk.subscribe({ kinds: [0], authors: [event.pubkey] }, {closeOnEose: true, groupable: true});
                    profileSubAuth.on("event", (pevent: NDKEvent) => {
                        addProfile(pevent);
                    });
                }
                addPost(event);
            });
        });
            
        ndkPool.on("relay:disconnect", (relay: NDKRelay) => {
            kind1Sub.stop()
            addToStatus("disconnected: " + relay.url);
        });

        ndkPool.on("relay:connect", (relay: NDKRelay) => {
            addToStatus("connected: " + relay.url);
            wipePosts();
            if(!auth) {
                kind1Sub = ndk.subscribe({ kinds: [1], limit: relayLimit }, {closeOnEose: false, groupable: false});
                kind1Sub.on("event", (event: NDKEvent) => {
                    // do profile lookups on the fly
                    if(lookupProfileName(event.pubkey) == event.pubkey) {
                        const profileSubAuth = ndk.subscribe({ kinds: [0], authors: [event.pubkey] }, {closeOnEose: true, groupable: true});
                        profileSubAuth.on("event", (pevent: NDKEvent) => {
                            addProfile(pevent);
                        });
                    }
                    addPost(event);
                });
            }
        });

        ndkPool.on("relay:connecting", (relay: NDKRelay) => {
            //addToStatus("connecting: " + relay.url);
        });

        ndk.addExplicitRelay(nrelaydata, NDKRelayAuthPolicies.signIn({ndk}), true);
    }

useEffect(() => {
        grabStuff(nrelaydata, useAuth == "true");
    }, []);
}    
    


@pablof7z
Copy link
Collaborator

Thanks for all this! I am writing documentation on the docs directory with tutorials and stuff like that

I would absolutely love it if you could spend some time to contribute some docs on what could have helped you understand how all this works; I am very close to NDK's inténtale (I wrote them! 😂) so there's probably a lot of stuff that you can see that I can't because of that

What's your npub btw?

@jeremyd
Copy link
Contributor Author

jeremyd commented Jul 1, 2024

Thanks for all this! I am writing documentation on the docs directory with tutorials and stuff like that

I would absolutely love it if you could spend some time to contribute some docs on what could have helped you understand how all this works; I am very close to NDK's inténtale (I wrote them! 😂) so there's probably a lot of stuff that you can see that I can't because of that

What's your npub btw?

No problem, I'd be happy to contribute. Let me know if you have a branch you're currently working on for the docs or just main branch. Some of the things from code snippits in the code comments did not work for me, so I will reproduce and make sure those are addressed. I'm still learning a lot (i filed a separate issue for I can't even seem to turn on debug haha). It looks like I'm going to be rolling with ndk for my project so contribution is the name of my game and I'll keep flowing with the issues, PRs and etc. :) I'll tag you on nostr so you have my npub.

@pablof7z
Copy link
Collaborator

pablof7z commented Jul 1, 2024

I'm writing docs and tutorials on the /docs directory and they are deployed here https://nostr-dev-kit.github.io/ndk

@jeremyd
Copy link
Contributor Author

jeremyd commented Jul 1, 2024

Cool, while testing this morning I realized I had *not backed out all changes, and that auth actually is broken in master. I will corral and test these changes and push them up. PR incoming..

@jeremyd jeremyd reopened this Jul 1, 2024
jeremyd pushed a commit to jeremyd/ndk that referenced this issue Jul 1, 2024
@jeremyd
Copy link
Contributor Author

jeremyd commented Jul 1, 2024

While this commit does un-stick authentication for a successful authentication. When authentication fails (relay rejects the auth) an error is thrown:

index.js:773 Uncaught (in promise) 
Error: auth-required: invalid auth received
    at Relay.handleNext (index.js:773:23)
    at Relay.runQueue (index.js:712:26)
    at Relay._onmessage (index.js:852:12)

I will need to think about this further, as I would like to be able to detect authentication failure and show a nice message to the user. Any thoughts appreciated. I think this error is coming from nostr-tools..

jeremyd pushed a commit to jeremyd/ndk that referenced this issue Jul 1, 2024
…hentication failed by adding relay authfail event.
@jeremyd
Copy link
Contributor Author

jeremyd commented Jul 1, 2024

A bonus of catching this error is that it doesn't infinitely keep asking the user to sign these auth requests. It fails once, and then doesn't ask again..

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants