Skip to content

feat: passing through onfeedauthentication hook #14

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

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Creates a new SwarmNetworker that will open replication streams on the `corestor
id: crypto.randomBytes(32), // A randomly-generated peer ID,
keyPair: HypercoreProtocol.keyPair(), // A NOISE keypair that's used across all connections.
onauthenticate: (remotePublicKey, cb) => { cb() }, // A NOISE keypair authentication hook
onfeedauthenticate: (feed, remotePublicKey, cb) => { cb() }, // A NOISE protocol authentication hook per feed
}
```

Expand Down
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class CorestoreNetworker extends Nanoresource {
encrypt: true,
live: true,
keyPair: this.keyPair,
onauthenticate: opts.onauthenticate
onauthenticate: opts.onauthenticate,
onfeedauthenticate: opts.onfeedauthenticate
}

this.streams = new Set()
Expand Down
96 changes: 96 additions & 0 deletions test/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,102 @@ test('onauthentication hook', async t => {
t.end()
})

test.only('onfeedauthentication hook blocks replication in either direction', async t => {
const keyPair1 = HypercoreProtocol.keyPair()
const keyPair2 = HypercoreProtocol.keyPair()
const { increment, done: allAuthenticationDone } = countTo(6)
const passedAuthentications = {}
const { networker: networker1, store: store1 } = await create({
keyPair: keyPair1,
onfeedauthenticate
})
const { networker: networker2, store: store2 } = await create({
keyPair: keyPair2,
onfeedauthenticate
})
const core1a = store1.get()
await append(core1a, 'a')
const core1b = store1.get()
await append(core1b, 'b')
const core1c = store1.get()
await append(core1c, 'c')
const core2a = store2.get({ key: core1a.key })
const core2b = store2.get({ key: core1b.key })
const core2c = store2.get({ key: core1c.key })

await networker1.configure(core1a.discoveryKey)
await networker1.configure(core1b.discoveryKey)
await networker1.configure(core1c.discoveryKey)
await networker2.configure(core2a.discoveryKey)
await networker2.configure(core2b.discoveryKey)
await networker2.configure(core2c.discoveryKey)

await allAuthenticationDone
await new Promise(resolve => setTimeout(resolve, 100))

t.equals(core2a.length, 1, 'replicated core2a')
t.equals(core2b.length, 0, 'blocked replication of core2b')
t.equals(core2c.length, 0, 'blocked replication of core2c')
await cleanup([networker1, networker2])
t.end()

function onfeedauthenticate (feed, peerPublicKey, cb) {
const remotePeer =
Buffer.compare(peerPublicKey, keyPair1.publicKey) === 0 ? 1 :
Buffer.compare(peerPublicKey, keyPair2.publicKey) === 0 ? 2 :
0

if (remotePeer === 0) {
t.fail('unexpeced key:' + peerPublicKey)
return
}

const core =
remotePeer === 2 ? (
feed === core1a ? 'a' :
feed === core1b ? 'b' :
feed === core1c ? 'c' :
null
) :
remotePeer === 1 ? (
feed === core2a ? 'a' :
feed === core2b ? 'b' :
feed === core2c ? 'c' :
null
) :
null

if (core === null) {
t.fail('unexpected feed:' + feed + ' for key ' + peerPublicKey)
return
}
const id = `core${remotePeer}${core}`
const error = (id === 'core1b' || id === 'core2c') ? new Error('prevent replication') : null
if (!passedAuthentications[id]) {
passedAuthentications[id] = true
t.pass(`${id}: ${error ? 'error': 'ok'}`)
increment()
}
cb(error)
}

function countTo (amount) {
let counted = 0
let _resolve
return {
done: new Promise(resolve => { _resolve = resolve }),
increment: () => {
counted += 1
if (counted === amount) {
_resolve()
} else if (counted > amount) {
t.fail('unexpected amount of calls')
}
}
}
}
})

async function create (opts = {}) {
if (!bootstrap) {
bootstrap = dht({
Expand Down