mirror of
https://github.com/fluencelabs/js-libp2p-secio
synced 2025-05-17 00:11:20 +00:00
Merge pull request #2 from ipfs/baseline-test
Add base line test and fix issues with handshaking
This commit is contained in:
commit
77709c3320
@ -28,20 +28,21 @@
|
|||||||
"debug": "^2.2.0",
|
"debug": "^2.2.0",
|
||||||
"duplexify": "^3.4.3",
|
"duplexify": "^3.4.3",
|
||||||
"length-prefixed-stream": "^1.5.0",
|
"length-prefixed-stream": "^1.5.0",
|
||||||
"libp2p-crypto": "^0.3.1",
|
"libp2p-crypto": "^0.4.0",
|
||||||
"multihashing": "^0.2.1",
|
"multihashing": "^0.2.1",
|
||||||
"node-forge": "^0.6.39",
|
"node-forge": "^0.6.39",
|
||||||
"peer-id": "^0.6.6",
|
"peer-id": "^0.6.6",
|
||||||
"protocol-buffers": "^3.1.6",
|
"protocol-buffers": "^3.1.6",
|
||||||
"readable-stream": "1.1.13",
|
"readable-stream": "1.1.13",
|
||||||
"run-series": "^1.1.4"
|
"run-series": "^1.1.4",
|
||||||
|
"through2": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aegir": "^3.0.4",
|
"aegir": "^3.0.4",
|
||||||
"bl": "^1.1.2",
|
"bl": "^1.1.2",
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"pre-commit": "^1.1.3",
|
"pre-commit": "^1.1.3",
|
||||||
"through2": "^2.0.1"
|
"stream-pair": "^1.0.3"
|
||||||
},
|
},
|
||||||
"pre-commit": [
|
"pre-commit": [
|
||||||
"lint",
|
"lint",
|
||||||
|
38
src/etm.js
38
src/etm.js
@ -2,38 +2,36 @@
|
|||||||
|
|
||||||
const through = require('through2')
|
const through = require('through2')
|
||||||
const lpm = require('length-prefixed-stream')
|
const lpm = require('length-prefixed-stream')
|
||||||
const forge = require('node-forge')
|
|
||||||
|
|
||||||
const createBuffer = forge.util.createBuffer
|
const toForgeBuffer = require('./support').toForgeBuffer
|
||||||
|
|
||||||
exports.writer = function etmWriter (insecure, cipher, mac) {
|
exports.writer = function etmWriter (insecure, cipher, mac) {
|
||||||
const encode = lpm.encode()
|
const encode = lpm.encode()
|
||||||
const pt = through(function (chunk, enc, cb) {
|
const pt = through(function (chunk, enc, cb) {
|
||||||
cipher.update(createBuffer(chunk.toString('binary')))
|
cipher.update(toForgeBuffer(chunk))
|
||||||
|
|
||||||
if (cipher.output.length() > 0) {
|
if (cipher.output.length() > 0) {
|
||||||
const data = new Buffer(cipher.output.getBytes(), 'binary')
|
const data = new Buffer(cipher.output.getBytes(), 'binary')
|
||||||
mac.update(data)
|
mac.update(data)
|
||||||
this.push(Buffer.concat([
|
const macBuffer = new Buffer(mac.getMac().getBytes(), 'binary')
|
||||||
data,
|
|
||||||
new Buffer(mac.digest(), 'binary')
|
this.push(Buffer.concat([data, macBuffer]))
|
||||||
]))
|
|
||||||
// reset hmac
|
// reset hmac
|
||||||
mac.start()
|
mac.start(null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
cb()
|
cb()
|
||||||
})
|
})
|
||||||
|
|
||||||
return insecure.pipe(pt).pipe(encode)
|
pt.pipe(encode).pipe(insecure)
|
||||||
|
|
||||||
|
return pt
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.reader = function etmReader (insecure, decipher, mac) {
|
exports.reader = function etmReader (insecure, decipher, mac) {
|
||||||
const decode = lpm.decode()
|
const decode = lpm.decode()
|
||||||
const pt = through(function (chunk, enc, cb) {
|
const pt = through(function (chunk, enc, cb) {
|
||||||
const l = chunk.length
|
const l = chunk.length
|
||||||
|
|
||||||
// TODO: check that this mac.getMac().length() is correct
|
|
||||||
const macSize = mac.getMac().length()
|
const macSize = mac.getMac().length()
|
||||||
|
|
||||||
if (l < macSize) {
|
if (l < macSize) {
|
||||||
@ -44,17 +42,19 @@ exports.reader = function etmReader (insecure, decipher, mac) {
|
|||||||
const data = chunk.slice(0, mark)
|
const data = chunk.slice(0, mark)
|
||||||
const macd = chunk.slice(mark)
|
const macd = chunk.slice(mark)
|
||||||
|
|
||||||
mac.update(data)
|
// Clear out any previous data
|
||||||
const expected = new Buffer(mac.digest(), 'binary')
|
mac.start(null, null)
|
||||||
// reset hmac
|
|
||||||
mac.start()
|
|
||||||
|
|
||||||
|
mac.update(data)
|
||||||
|
const expected = new Buffer(mac.getMac().getBytes(), 'binary')
|
||||||
|
// reset hmac
|
||||||
|
mac.start(null, null)
|
||||||
if (!macd.equals(expected)) {
|
if (!macd.equals(expected)) {
|
||||||
return cb(new Error(`MAC Invalid: ${macd} != ${expected}`))
|
return cb(new Error(`MAC Invalid: ${macd.toString('hex')} != ${expected.toString('hex')}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
// all good, decrypt
|
// all good, decrypt
|
||||||
decipher.update(data)
|
decipher.update(toForgeBuffer(data))
|
||||||
|
|
||||||
if (decipher.output.length() > 0) {
|
if (decipher.output.length() > 0) {
|
||||||
const data = new Buffer(decipher.output.getBytes(), 'binary')
|
const data = new Buffer(decipher.output.getBytes(), 'binary')
|
||||||
@ -64,5 +64,7 @@ exports.reader = function etmReader (insecure, decipher, mac) {
|
|||||||
cb()
|
cb()
|
||||||
})
|
})
|
||||||
|
|
||||||
return insecure.pipe(decode).pipe(pt)
|
insecure.pipe(decode).pipe(pt)
|
||||||
|
|
||||||
|
return pt
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@ const fs = require('fs')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const protobuf = require('protocol-buffers')
|
const protobuf = require('protocol-buffers')
|
||||||
|
|
||||||
const log = debug('libp2p:secio:handshake')
|
const log = debug('libp2p:secio')
|
||||||
log.error = debug('libp2p:secio:handshake:error')
|
log.error = debug('libp2p:secio:error')
|
||||||
|
|
||||||
const pbm = protobuf(fs.readFileSync(path.join(__dirname, '../secio.proto')))
|
const pbm = protobuf(fs.readFileSync(path.join(__dirname, '../secio.proto')))
|
||||||
|
|
||||||
@ -18,17 +18,18 @@ const support = require('../support')
|
|||||||
module.exports = function exchange (session, cb) {
|
module.exports = function exchange (session, cb) {
|
||||||
log('2. exchange - start')
|
log('2. exchange - start')
|
||||||
|
|
||||||
let eResult
|
let genSharedKey
|
||||||
|
let exchangeOut
|
||||||
|
|
||||||
try {
|
try {
|
||||||
eResult = crypto.generateEphemeralKeyPair(session.local.curveT)
|
const eResult = crypto.generateEphemeralKeyPair(session.local.curveT)
|
||||||
|
session.local.ephemeralPubKey = eResult.key
|
||||||
|
genSharedKey = eResult.genSharedKey
|
||||||
|
exchangeOut = makeExchange(session)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return cb(err)
|
return cb(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
session.local.ephemeralPubKey = eResult.key
|
|
||||||
const genSharedKey = eResult.genSharedKey
|
|
||||||
const exchangeOut = makeExchange(session)
|
|
||||||
|
|
||||||
session.insecureLp.write(exchangeOut)
|
session.insecureLp.write(exchangeOut)
|
||||||
session.insecureLp.once('data', (chunk) => {
|
session.insecureLp.once('data', (chunk) => {
|
||||||
const exchangeIn = pbm.Exchange.decode(chunk)
|
const exchangeIn = pbm.Exchange.decode(chunk)
|
||||||
@ -53,17 +54,16 @@ function makeExchange (session) {
|
|||||||
session.proposal.in,
|
session.proposal.in,
|
||||||
session.local.ephemeralPubKey
|
session.local.ephemeralPubKey
|
||||||
])
|
])
|
||||||
return pbm.Exchange({
|
const epubkey = session.local.ephemeralPubKey
|
||||||
epubkey: session.local.ephemeralPubKey,
|
const signature = session.localKey.sign(selectionOut)
|
||||||
signature: session.localKey.sign(selectionOut)
|
|
||||||
})
|
return pbm.Exchange.encode({epubkey, signature})
|
||||||
}
|
}
|
||||||
|
|
||||||
function verify (session, exchangeIn) {
|
function verify (session, exchangeIn) {
|
||||||
log('2.1. verify')
|
log('2.1. verify')
|
||||||
|
|
||||||
session.remote.ephemeralPubKey = exchangeIn.epubkey
|
session.remote.ephemeralPubKey = exchangeIn.epubkey
|
||||||
|
|
||||||
const selectionIn = Buffer.concat([
|
const selectionIn = Buffer.concat([
|
||||||
session.proposal.in,
|
session.proposal.in,
|
||||||
session.proposal.out,
|
session.proposal.out,
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
const duplexify = require('duplexify')
|
const duplexify = require('duplexify')
|
||||||
const debug = require('debug')
|
const debug = require('debug')
|
||||||
const log = debug('libp2p:secio:handshake')
|
const log = debug('libp2p:secio')
|
||||||
log.error = debug('libp2p:secio:handshake:error')
|
log.error = debug('libp2p:secio:error')
|
||||||
|
|
||||||
const etm = require('../etm')
|
const etm = require('../etm')
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ module.exports = function finish (session, cb) {
|
|||||||
const r = etm.reader(session.insecure, session.remote.cipher, session.remote.mac)
|
const r = etm.reader(session.insecure, session.remote.cipher, session.remote.mac)
|
||||||
session.secure = duplexify(w, r)
|
session.secure = duplexify(w, r)
|
||||||
|
|
||||||
session.secure.write(session.proposal.in.rand)
|
session.secure.write(session.proposal.randIn)
|
||||||
|
|
||||||
// read our nonce back
|
// read our nonce back
|
||||||
session.secure.once('data', (nonceOut2) => {
|
session.secure.once('data', (nonceOut2) => {
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
const debug = require('debug')
|
const debug = require('debug')
|
||||||
const series = require('run-series')
|
const series = require('run-series')
|
||||||
|
|
||||||
const log = debug('libp2p:secio:handshake')
|
const log = debug('libp2p:secio')
|
||||||
log.error = debug('libp2p:secio:handshake:error')
|
log.error = debug('libp2p:secio:error')
|
||||||
|
|
||||||
const propose = require('./propose')
|
const propose = require('./propose')
|
||||||
const exchange = require('./exchange')
|
const exchange = require('./exchange')
|
||||||
|
@ -9,8 +9,8 @@ const PeerId = require('peer-id')
|
|||||||
const mh = require('multihashing')
|
const mh = require('multihashing')
|
||||||
const crypto = require('libp2p-crypto')
|
const crypto = require('libp2p-crypto')
|
||||||
|
|
||||||
const log = debug('libp2p:secio:handshake')
|
const log = debug('libp2p:secio')
|
||||||
log.error = debug('libp2p:secio:handshake:error')
|
log.error = debug('libp2p:secio:error')
|
||||||
|
|
||||||
// nonceSize is the size of our nonces (in bytes)
|
// nonceSize is the size of our nonces (in bytes)
|
||||||
const nonceSize = 16
|
const nonceSize = 16
|
||||||
@ -23,17 +23,20 @@ const support = require('../support')
|
|||||||
module.exports = function propose (session, cb) {
|
module.exports = function propose (session, cb) {
|
||||||
log('1. propose - start')
|
log('1. propose - start')
|
||||||
|
|
||||||
const nonceOut = forge.random.getBytesSync(nonceSize)
|
const nonceOut = new Buffer(forge.random.getBytesSync(nonceSize), 'binary')
|
||||||
const proposeOut = makeProposal(session, nonceOut)
|
const proposeOut = makeProposal(session, nonceOut)
|
||||||
|
|
||||||
session.proposal.out = proposeOut
|
session.proposal.out = proposeOut
|
||||||
session.proposal.nonceOut = nonceOut
|
session.proposal.nonceOut = nonceOut
|
||||||
|
|
||||||
session.insecureLp.write(proposeOut)
|
session.insecureLp.write(proposeOut)
|
||||||
session.insecureLp.once('data', (chunk) => {
|
session.insecureLp.once('data', (chunk) => {
|
||||||
const proposeIn = readProposal(chunk)
|
let proposeIn
|
||||||
session.proposal.in = proposeIn
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
proposeIn = readProposal(chunk)
|
||||||
|
session.proposal.in = chunk
|
||||||
|
session.proposal.randIn = proposeIn.rand
|
||||||
identify(session, proposeIn)
|
identify(session, proposeIn)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return cb(err)
|
return cb(err)
|
||||||
@ -54,12 +57,12 @@ module.exports = function propose (session, cb) {
|
|||||||
// Generate and send Hello packet.
|
// Generate and send Hello packet.
|
||||||
// Hello = (rand, PublicKey, Supported)
|
// Hello = (rand, PublicKey, Supported)
|
||||||
function makeProposal (session, nonceOut) {
|
function makeProposal (session, nonceOut) {
|
||||||
session.local.permanentPubKey = session.localKey.getPublic()
|
session.local.permanentPubKey = session.localKey.public
|
||||||
const myPubKeyBytes = session.local.permanentPubKey.bytes
|
const myPubKeyBytes = session.local.permanentPubKey.bytes
|
||||||
|
|
||||||
return pbm.Propose({
|
return pbm.Propose.encode({
|
||||||
rand: nonceOut,
|
rand: nonceOut,
|
||||||
pubKey: myPubKeyBytes,
|
pubkey: myPubKeyBytes,
|
||||||
exchanges: support.exchanges.join(','),
|
exchanges: support.exchanges.join(','),
|
||||||
ciphers: support.ciphers.join(','),
|
ciphers: support.ciphers.join(','),
|
||||||
hashes: support.hashes.join(',')
|
hashes: support.hashes.join(',')
|
||||||
@ -67,14 +70,14 @@ function makeProposal (session, nonceOut) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readProposal (bytes) {
|
function readProposal (bytes) {
|
||||||
return pbm.Proposal.decode(bytes)
|
return pbm.Propose.decode(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
function identify (session, proposeIn) {
|
function identify (session, proposeIn) {
|
||||||
log('1.1 identify')
|
log('1.1 identify')
|
||||||
|
|
||||||
session.remote.permanentPubKey = crypto.unmarshalPublicKey(proposeIn.pubKey)
|
session.remote.permanentPubKey = crypto.unmarshalPublicKey(proposeIn.pubkey)
|
||||||
session.remotePeer = PeerId.createFromPubKey(session.remote.permanentPubKey)
|
session.remotePeer = PeerId.createFromPubKey(proposeIn.pubkey.toString('base64'))
|
||||||
|
|
||||||
log('1.1 identify - %s - identified remote peer as %s', session.localPeer.toB58String(), session.remotePeer.toB58String())
|
log('1.1 identify - %s - identified remote peer as %s', session.localPeer.toB58String(), session.remotePeer.toB58String())
|
||||||
}
|
}
|
||||||
@ -91,7 +94,7 @@ function selection (session, nonceOut, proposeIn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const remote = {
|
const remote = {
|
||||||
pubKeyBytes: proposeIn.pubKey,
|
pubKeyBytes: proposeIn.pubkey,
|
||||||
exchanges: proposeIn.exchanges.split(','),
|
exchanges: proposeIn.exchanges.split(','),
|
||||||
hashes: proposeIn.hashes.split(','),
|
hashes: proposeIn.hashes.split(','),
|
||||||
ciphers: proposeIn.ciphers.split(','),
|
ciphers: proposeIn.ciphers.split(','),
|
||||||
@ -113,8 +116,14 @@ function selection (session, nonceOut, proposeIn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectBest (local, remote) {
|
function selectBest (local, remote) {
|
||||||
const oh1 = digest(Buffer.concat(remote.pubKeyBytes, local.nonce))
|
const oh1 = digest(Buffer.concat([
|
||||||
const oh2 = digest(Buffer.concat(local.pubKeyBytes, remote.nonce))
|
remote.pubKeyBytes,
|
||||||
|
local.nonce
|
||||||
|
]))
|
||||||
|
const oh2 = digest(Buffer.concat([
|
||||||
|
local.pubKeyBytes,
|
||||||
|
remote.nonce
|
||||||
|
]))
|
||||||
const order = Buffer.compare(oh1, oh2)
|
const order = Buffer.compare(oh1, oh2)
|
||||||
|
|
||||||
if (order === 0) {
|
if (order === 0) {
|
||||||
|
10
src/index.js
10
src/index.js
@ -14,6 +14,7 @@ exports.SecureSession = class SecureSession {
|
|||||||
this.remote = {}
|
this.remote = {}
|
||||||
this.proposal = {}
|
this.proposal = {}
|
||||||
this.insecure = insecure
|
this.insecure = insecure
|
||||||
|
this.secure = null
|
||||||
const e = lpstream.encode()
|
const e = lpstream.encode()
|
||||||
const d = lpstream.decode()
|
const d = lpstream.decode()
|
||||||
this.insecureLp = duplexify(e, d)
|
this.insecureLp = duplexify(e, d)
|
||||||
@ -39,9 +40,16 @@ exports.SecureSession = class SecureSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secureStream (cb) {
|
||||||
|
this.handshake((err) => {
|
||||||
|
if (err) return cb(err)
|
||||||
|
|
||||||
|
cb(null, this.secure)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
handshake (cb) {
|
handshake (cb) {
|
||||||
// TODO: figure out how to best handle the handshake timeout
|
// TODO: figure out how to best handle the handshake timeout
|
||||||
// TODO: better locking
|
|
||||||
if (this._handshakeLock) {
|
if (this._handshakeLock) {
|
||||||
return cb(new Error('handshake already in progress'))
|
return cb(new Error('handshake already in progress'))
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,7 @@ exports.exchanges = [
|
|||||||
|
|
||||||
exports.ciphers = [
|
exports.ciphers = [
|
||||||
'AES-256',
|
'AES-256',
|
||||||
'AES-128',
|
'AES-128'
|
||||||
'Blowfish'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
exports.hashes = [
|
exports.hashes = [
|
||||||
@ -57,6 +56,10 @@ const hashMap = {
|
|||||||
SHA512: forge.md.sha512.create()
|
SHA512: forge.md.sha512.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toForgeBuffer = exports.toForgeBuffer = (buf) => (
|
||||||
|
forge.util.createBuffer(buf.toString('binary'))
|
||||||
|
)
|
||||||
|
|
||||||
function makeMac (hashType, key) {
|
function makeMac (hashType, key) {
|
||||||
const hash = hashMap[hashType]
|
const hash = hashMap[hashType]
|
||||||
|
|
||||||
@ -65,7 +68,7 @@ function makeMac (hashType, key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mac = forge.hmac.create()
|
const mac = forge.hmac.create()
|
||||||
mac.start(hash, key)
|
mac.start(hash, toForgeBuffer(key))
|
||||||
return mac
|
return mac
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,8 +76,8 @@ function makeCipher (cipherType, iv, key) {
|
|||||||
if (cipherType === 'AES-128' || cipherType === 'AES-256') {
|
if (cipherType === 'AES-128' || cipherType === 'AES-256') {
|
||||||
// aes in counter (CTR) mode because that is what
|
// aes in counter (CTR) mode because that is what
|
||||||
// is used in go (cipher.NewCTR)
|
// is used in go (cipher.NewCTR)
|
||||||
const cipher = forge.cipher.createCipher('AES-CTR', key)
|
const cipher = forge.cipher.createCipher('AES-CTR', toForgeBuffer(key))
|
||||||
cipher.start({iv})
|
cipher.start({iv: toForgeBuffer(iv)})
|
||||||
return cipher
|
return cipher
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,22 +5,18 @@ const expect = require('chai').expect
|
|||||||
const through = require('through2')
|
const through = require('through2')
|
||||||
const bl = require('bl')
|
const bl = require('bl')
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const duplexify = require('duplexify')
|
const crypto = require('libp2p-crypto')
|
||||||
|
const streamPair = require('stream-pair')
|
||||||
|
|
||||||
const secio = require('../src')
|
const SecureSession = require('../src').SecureSession
|
||||||
|
|
||||||
describe('libp2p-secio', () => {
|
describe('libp2p-secio', () => {
|
||||||
it('exists', () => {
|
|
||||||
expect(secio).to.exist
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('insecure length prefixed stream', () => {
|
describe('insecure length prefixed stream', () => {
|
||||||
it('encodes', (done) => {
|
it('encodes', (done) => {
|
||||||
const id = PeerId.create({bits: 64})
|
const id = PeerId.create({bits: 64})
|
||||||
const key = {}
|
const key = {}
|
||||||
const pt = through()
|
const insecure = through()
|
||||||
const insecure = duplexify(pt, pt)
|
const s = new SecureSession(id, key, insecure)
|
||||||
const s = new secio.SecureSession(id, key, insecure)
|
|
||||||
|
|
||||||
// encoded on raw
|
// encoded on raw
|
||||||
s.insecure.pipe(bl((err, res) => {
|
s.insecure.pipe(bl((err, res) => {
|
||||||
@ -37,9 +33,8 @@ describe('libp2p-secio', () => {
|
|||||||
it('decodes', (done) => {
|
it('decodes', (done) => {
|
||||||
const id = PeerId.create({bits: 64})
|
const id = PeerId.create({bits: 64})
|
||||||
const key = {}
|
const key = {}
|
||||||
const pt = through()
|
const insecure = through()
|
||||||
const insecure = duplexify(pt, pt)
|
const s = new SecureSession(id, key, insecure)
|
||||||
const s = new secio.SecureSession(id, key, insecure)
|
|
||||||
|
|
||||||
// encoded on raw
|
// encoded on raw
|
||||||
s.insecureLp.pipe(bl((err, res) => {
|
s.insecureLp.pipe(bl((err, res) => {
|
||||||
@ -52,5 +47,64 @@ describe('libp2p-secio', () => {
|
|||||||
s.insecure.write('\u0005world')
|
s.insecure.write('\u0005world')
|
||||||
s.insecureLp.end()
|
s.insecureLp.end()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('all together now', (done) => {
|
||||||
|
const pair = streamPair.create()
|
||||||
|
|
||||||
|
createSession(pair, (err, local) => {
|
||||||
|
if (err) throw err
|
||||||
|
createSession(pair.other, (err, remote) => {
|
||||||
|
if (err) throw err
|
||||||
|
|
||||||
|
remote.session.insecureLp.pipe(bl((err, res) => {
|
||||||
|
if (err) throw err
|
||||||
|
expect(res.toString()).to.be.eql('hello world')
|
||||||
|
done()
|
||||||
|
}))
|
||||||
|
|
||||||
|
local.session.insecureLp.write('hello ')
|
||||||
|
local.session.insecureLp.write('world')
|
||||||
|
pair.end()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('upgrades a connection', (done) => {
|
||||||
|
const pair = streamPair.create()
|
||||||
|
|
||||||
|
createSession(pair, (err, local) => {
|
||||||
|
if (err) throw err
|
||||||
|
createSession(pair.other, (err, remote) => {
|
||||||
|
if (err) throw err
|
||||||
|
|
||||||
|
local.session.secureStream((err, localSecure) => {
|
||||||
|
if (err) throw err
|
||||||
|
|
||||||
|
localSecure.write('hello world')
|
||||||
|
})
|
||||||
|
|
||||||
|
remote.session.secureStream((err, remoteSecure) => {
|
||||||
|
if (err) throw err
|
||||||
|
remoteSecure.once('data', (chunk) => {
|
||||||
|
expect(chunk.toString()).to.be.eql('hello world')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function createSession (insecure, cb) {
|
||||||
|
crypto.generateKeyPair('RSA', 2048, (err, key) => {
|
||||||
|
if (err) return cb(err)
|
||||||
|
const id = PeerId.createFromPrivKey(key.bytes)
|
||||||
|
cb(null, {
|
||||||
|
id,
|
||||||
|
key,
|
||||||
|
insecure,
|
||||||
|
session: new SecureSession(id, key, insecure)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user