mirror of
https://github.com/fluencelabs/js-libp2p-secio
synced 2025-04-22 21:32:16 +00:00
115 lines
2.5 KiB
JavaScript
115 lines
2.5 KiB
JavaScript
'use strict'
|
|
|
|
const duplexify = require('duplexify')
|
|
const lpstream = require('length-prefixed-stream')
|
|
const PassThrough = require('readable-stream').PassThrough
|
|
|
|
const handshake = require('./handshake')
|
|
|
|
exports.SecureSession = class SecureSession {
|
|
constructor (local, key, insecure) {
|
|
this.localKey = key
|
|
this.localPeer = local
|
|
this.sharedSecret = null
|
|
this.local = {}
|
|
this.remote = {}
|
|
this.proposal = {}
|
|
this.insecure = insecure
|
|
this.secure = null
|
|
const e = lpstream.encode()
|
|
const d = lpstream.decode()
|
|
this.insecureLp = duplexify(e, d)
|
|
|
|
e.pipe(this.insecure)
|
|
this.insecure.pipe(d)
|
|
|
|
if (!this.localPeer) {
|
|
throw new Error('no local id provided')
|
|
}
|
|
|
|
if (!this.localKey) {
|
|
throw new Error('no local private key provided')
|
|
}
|
|
|
|
// Enable when implemented in js-peer-id
|
|
// if (!this.localPeer.matchesPrivateKey(this.localKey)) {
|
|
// throw new Error('peer.ID does not match privateKey')
|
|
// }
|
|
|
|
if (!insecure) {
|
|
throw new Error('no insecure stream provided')
|
|
}
|
|
}
|
|
|
|
secureStream () {
|
|
let handshaked = false
|
|
const reader = new PassThrough()
|
|
const writer = new PassThrough()
|
|
const dp = duplexify(writer, reader)
|
|
const originalRead = reader.read.bind(reader)
|
|
const originalWrite = writer.write.bind(writer)
|
|
|
|
const doHandshake = () => {
|
|
if (handshaked) return
|
|
|
|
handshaked = true
|
|
|
|
// Restore methods to avoid overhead
|
|
reader.read = originalRead
|
|
writer.write = originalWrite
|
|
|
|
this.handshake((err) => {
|
|
if (err) return dp.emit('error', err)
|
|
|
|
// Pipe things together
|
|
writer.pipe(this.secure)
|
|
this.secure.pipe(reader)
|
|
dp.uncork()
|
|
})
|
|
}
|
|
|
|
// patch to detect first read
|
|
reader.read = (size) => {
|
|
doHandshake()
|
|
originalRead(size)
|
|
}
|
|
|
|
// patch to detect first write
|
|
writer.write = (chunk, encoding, callback) => {
|
|
doHandshake()
|
|
originalWrite(chunk, encoding, callback)
|
|
}
|
|
|
|
dp.cork()
|
|
|
|
return dp
|
|
}
|
|
|
|
handshake (cb) {
|
|
// TODO: figure out how to best handle the handshake timeout
|
|
if (this._handshakeLock) {
|
|
return cb(new Error('handshake already in progress'))
|
|
}
|
|
|
|
this._handshakeLock = true
|
|
|
|
const finish = (err) => {
|
|
this._handshakeLock = false
|
|
cb(err)
|
|
}
|
|
|
|
if (this._handshakeDone) {
|
|
return finish()
|
|
}
|
|
|
|
handshake(this, (err) => {
|
|
if (err) {
|
|
return finish(err)
|
|
}
|
|
|
|
this._handshakeDone = true
|
|
finish()
|
|
})
|
|
}
|
|
}
|