Skip to content

Conversation

@martinheidegger
Copy link
Contributor

Having a stream authentication is super-useful but it may be warranted to authenticate particular feeds to particular peers while others are supposed to work. The proposed API in this PR should work without much overhead, allowing to disable the replication for particular feeds.

@RangerMauve
Copy link
Contributor

This would be amazing to have since we could have really flexible access control restrictions.

lib/replicate.js Outdated
if (opts.onfeedauthenticate) {
if (!stream.remotePublicKey) {
stream.once('handshake', function () {
onready()
Copy link
Contributor

Choose a reason for hiding this comment

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

it's not safe to call onready again as it that will mess with the ifAvailable counter

Copy link
Contributor

Choose a reason for hiding this comment

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

If you call ifAvailable .wait() it might be fine I think

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the feedback. I will try to address it, also 😨 I fear that won't be enough as the 'handshake' event may never occur (in case of error, or close) as such i probably need to listen/unlisten to other events as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea it's tricky. You need to hook up on(close) as well and call the ifavailable hook but ONLY if the happy path hasn't succeded.

lib/replicate.js Outdated
}
if (opts.onfeedauthenticate) {
if (!stream.remotePublicKey) {
stream.once('handshake', function () {
Copy link
Contributor

Choose a reason for hiding this comment

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

prob have to setMaxListeners(0) here to avoid leak warnings if we use the event for flow control.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was wondering about this: .setMaxListeners on stream is weird in this location, shouldn't it be in the Protocol constructor of hypercore-protocol as the stream may be passed-in from the outside. (here maybe?) Anyways I will add it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I normally avoid events for flow control in general because of this, but unsure if you can do this without it. Since this is the one taking on the responsibility of adding that listener, I'd put it here, so it's clear that we aren't just suppressing a leak from the outside.

@martinheidegger
Copy link
Contributor Author

@mafintosh in the just pushed 9c93de3 I think I managed to take care of closing eventually opened event handlers using ifavailable before/after all possible delays; guarding against closing of stream/parallel replication at any point. Does that work for you?

if (stream.destroyed) return
if (stream.opened(feed.key)) return
feed.ifAvailable.wait()
opts.onfeedauthenticate(feed, stream.remotePublicKey, function (err) {
Copy link
Contributor

Choose a reason for hiding this comment

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

why is the feed passed actually? is that because this is a corestore feature in practice?

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 just pass the discoveryKey it's a lot easier to port to the stream layer later on.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am passing the feed for an authentication method to have a bit more flexibility in choosing what to authenticate, such as: discoveryKey, publicKey, or size limits etc.

Copy link
Contributor

Choose a reason for hiding this comment

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

How is that different than doing:

feed.replicate({
  onfeedauthenticate (remotePublicKey, done) {
    if (feed.....) 
  }
})

Copy link
Contributor Author

@martinheidegger martinheidegger May 5, 2021

Choose a reason for hiding this comment

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

is that because this is a corestore feature in practice?

Yes, in a sense. This hook is for allowing selected feeds over a single stream. If the API doesn't provide information on which stream is replicated, we could bind the functions:

const feedA, feedB

function commonAuthLogic (feed, remotePublicKey, done) {}

feedA.replicate({ onfeedauthenticate: commonAuthLogic.bind(null, feedA) })
feedB.replicate({ onfeedauthenticate: commonAuthLogic.bind(null, feedB) })

but that is problematic if the overarching system (such as corestore) simply passes-on the replication options and doesn't manage the onfeedauthenticate logic.

new Corestore({
  onfeedauthenticate () {
    /* which feed? */
  }
})

Possibly requiring some packages to be aware of that logic.

A different question is what kind of identification to use. Initially I thought of using the hypercore.key as identifier. It is used in corestore.get(). But because of hyperswarm using discoveryKey I thought maybe discoveryKey as an identifier, as its the key for hyperswarm. Both keys in the API seem like overkill, which is why I went with simply the feed. The instance was there and it didn't seem harmful.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok 👍 It seems a bit weird that we add a "corestore/other-many-core" feature here then, as I think that should be implemented there but we can try it out - ie it might be removed in a future major.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I hope it won't cause trouble down the road.

@mafintosh
Copy link
Contributor

Yep I think it looks good.

There is an edgecase where the hook runs more than once for the same feed, but I don't think that can be avoided when implemented here. In general it's a more complicated than I prefer, but that's due to the actual stream hook not being exposed. In retrospect it would probably be a lot easier to implement on the replication stream itself as that can have a simple hook here https://github.com/mafintosh/simple-hypercore-protocol/blob/master/index.js#L185 i think, but we can start with this.

Asked a usage question above, cause was a bit confused after rereading it, but other than that it should be fine. Thanks for adding tests.

@martinheidegger
Copy link
Contributor Author

In retrospect it would probably be a lot easier to implement on the replication stream itself as that can have a simple hook here https://github.com/mafintosh/simple-hypercore-protocol/blob/master/index.js#L185 i think, but we can start with this.

I was aware of this possibility, but I don't see the problem in practice: Before the ready hook, random-access-storage operations and other delayed checks may also happen more than once, resulting in unintuitive behavior.

Finding the right layer to put things in has been stressful 😅. The send method seems an interesting choice for it (I wonder what your thought process is). I would may have gone with the onopen method of hypercore-protocol but I am feeling less secure to touch even lower levels of the API 😅

@mafintosh
Copy link
Contributor

mafintosh commented May 5, 2021

@martinheidegger can you remove the commit from the other PR you made, that I just merged? then this should be good to go.

@martinheidegger
Copy link
Contributor Author

rebased and squashed in b6de219

@mafintosh mafintosh merged commit 04d2cca into holepunchto:master May 5, 2021
@martinheidegger martinheidegger deleted the onfeedauthenticate branch May 5, 2021 15:16
@mafintosh
Copy link
Contributor

Thanks, 9.10.0

@mafintosh
Copy link
Contributor

(contains the other pr also)

@RangerMauve
Copy link
Contributor

This is super exciting. Thank you both for getting this functionality in. 💜

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants