nostr-protocol / nips

Nostr Implementation Possibilities
2.39k stars 579 forks source link

NIP-7: support multiple extensions. #353

Open BlowaterNostr opened 1 year ago

BlowaterNostr commented 1 year ago

Background: During a test of https://blowater.deno.dev/, some users have both nos2x and alby installed and they found nos2x and alby had slightly different behaviors, at least when integrating with blowater. The user had to disable nos2x and then enable Alby.

I suggest for NIP-7 to support multiple extensions because in the future there might be more extensions that support Nostr. User should be able to choose if they happen to install multiple.

This is related to https://github.com/nostr-protocol/nips/issues/279

But supporting NIP-7 will be a breaking change because the namespace needs to be something like

window.nostr = [ext1, ext2, ...]

Following your discussion in #279 , maybe we should have a new NIP for this functionality and gradually retire NIP7

fiatjaf commented 1 year ago

What were the slight differences? I think it is easier if we call @bumi here and agree on the implementation and fix nos2x or alby so they are compatible.

bumi commented 1 year ago

I think the main question is if parallel calls are possible. at Alby we block those and could improve how we communicate this back to the client or implement some queuing of the calls. (The user must only get one prompt when an app is accessed) But in terms of spec I think NIP07 is clear and apps are compatible.

supporting multiple extensions at the same time will be not possible because the extensions do not know of each other. Even if it is possible to define window.nostr as an array I don't think this will lead to better UX. Users can enable/disable extensions on the browser level.

fiatjaf commented 1 year ago

I see, so I think it's all fine.

I've started blocking calls on nos2x too, although I haven't released that yet because I need some time to test. I agree that is independent of the spec.

fiatjaf commented 1 year ago

By the way, I think Alby could not include window.nostr unless there is a private key set there. That allows people to use Alby just for the Lightning wallet while using other extensions for Nostr.

I guess nos2x should probably do that too, even though it doesn't do anything besides Nostr it still includes window.nostr when there is no private key set.

bumi commented 1 year ago

By the way, I think Alby could not include window.nostr unless there is a private key set there. That allows people to use Alby just for the Lightning wallet while using other extensions for Nostr.

that's how it is done. If no key is configured we don't include window.nostr - some had been confused about this, but I think it is best and as you say most flexible for the users.

BlowaterNostr commented 1 year ago

Correct me if wrong, how is a NFT market such as OpenSea or Magic Eden able to connect to different wallet? This is not from the bitcoin community because shouldn't the extension part similar?

If we don't support multiple extensions, what should be the behavior of applications when a user has >= 2 extensions with Nostr account enabled?

BlowaterNostr commented 1 year ago

Received another user feedback about multiple extensions. I believe this is a real issue.

1. Client developer clarity

For example, if I enable both nos2x and alby image

I will get image The reason is that, maybe because I installed nos2x after alby, therefore, nos2x's window.nostr object override alby's .nostr object.

nostr.enable is an alby method.

There is no way, from the client application code, to tell which extension I am working with.

2. Allow user to choose which extension to use

The user can store different keys in different extensions, they should be able to choose instead of relying on which extension happens to own the window.nostr object.

BlowaterNostr commented 1 year ago

Instead of using an array, we can use different suffix. For example

window.nostr_nos2x
window.nostr_alby
window.nostr_other

We can still keep

window.nostr

for compatibility and convenience but recommend the suffix way.

@bumi Extensions do not need to know each other in this approach.

ROBO358 commented 1 year ago

I think you should support multiple NIP-07 extensions. At this time, it is assumed that a user who has multiple extensions installed will have a different private key for each extension, so it is necessary for the user to be able to select which extension to use. think. Also, I would prefer not to have a fixed suffix for each extension, as the client won't know all the extensions that are added in the future.

digi-monkey commented 1 year ago

Instead of using an array, we can use different suffix. For example

window.nostr_nos2x
window.nostr_alby
window.nostr_other

We can still keep

window.nostr

for compatibility and convenience but recommend the suffix way.

@bumi Extensions do not need to know each other in this approach.

I think the suffix way is not very ideal. clients needs to know too many nostr instance with different names. I would love a array way to include multiple extensions under the instance of window.nostr2 or window.nostrWallet in the pages and we leave window.nostr for forward compatibility, also, we add method like nostr2.getExtenstionVersion(extensionId: string) / nostrWallet.getExtenstionVersion(extensionId: string) in the new specs so client can request and display each extension info to let user choose which one to connect

BlowaterNostr commented 1 year ago

@digi-monkey The challenge of having an array is, suppose this is an array

window.nostr_array

nostr_array becomes a shared object among all extensions, which will be very hard for extension developers to debug.

The suffix way is not convenient for client developers. But it might be desired, at least for some client developers.

For example, as a client developer, I would like to only integrate with extensions that I have tested and trust.

But it's really up to extension developers such as @fiatjaf and @bumi to decide how they want to implement it.

fiatjaf commented 1 year ago

Sorry, but I don't see the point of this. Why do you need two extensions with Nostr keys on both? Is that because you have multiple "accounts"? In that case you should definitely write a single extension that supports multiple accounts -- or use multiple browsers, multiple browser "containers" and whatnot,

What I'm trying to say is that this is a niche use case that can be fixed by software and user behavior, we don't need to throw away an existing spec with multiple implementations in order to solve this.

ROBO358 commented 1 year ago

I'm concerned that extensions that don't work well (and aren't well-supported) can cause problems. For example, if an extension has a bug that works regardless of the user's intention or a bug that does not allow asynchronous processing, the client cannot take measures to disable the extension (or avoid the problem).

What I think is important about supporting these multiple extensions is that the extension name is available to the client.

fiatjaf commented 1 year ago

I don't understand, you can't fix broken software with another spec. If the extension doesn't work then you should remove it.

npub1zenn0 commented 1 year ago

I already posted this in the wrong issue, but I'm reposting here. Sorry for the noise.

I think a push-based login system works better. Rather than having user click a login button on a web page, I'd have the user click the extension button. That'd then send a regular DOM custom event to the web page, and the flow would go from there.

That has a couple of advantages:

Disadvantages:

I already made a prototype of this flow a while back. This one works only on Chrome/ium because service_worker key, but the concept is the same on Firefox (except the event has to be JSON.stringified because website script can't access an object).

Giszmo commented 10 months ago

I like @npub1zenn0 's idea for the reasons mentioned. It would also fix the multi-account use case I think. If Alice uses alby and Bob and Carol use nos2x, switching from Alice to Bob would simply result in nos2x overwriting the window.nostr object in the process.

Also even though the full beauty of this new way of injecting the nostr object would require the client dev's support, an extension could still fire the login and provide the nostr object for any legacy clients to then use the nostr object.