|
@ -93,73 +93,58 @@ CryptoStream.prototype.destroy = function(err) { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function CleartextStream (pair) { |
|
|
// Move decrypted, clear data out into the application.
|
|
|
CryptoStream.call(this, pair); |
|
|
// From the user's perspective this occurs as a 'data' event
|
|
|
} |
|
|
// on the pair.cleartext.
|
|
|
util.inherits(CleartextStream, CryptoStream); |
|
|
// also
|
|
|
|
|
|
// Move encrypted data to the stream. From the user's perspective this
|
|
|
|
|
|
// occurs as a 'data' event on the pair.encrypted. Usually the application
|
|
|
// Push in any clear data coming from the application.
|
|
|
// will have some code which pipes the stream to a socket:
|
|
|
// This arrives via some code like this:
|
|
|
|
|
|
//
|
|
|
//
|
|
|
// pair.cleartext.write("hello world");
|
|
|
// pair.encrypted.on('data', function (d) {
|
|
|
|
|
|
// socket.write(d);
|
|
|
|
|
|
// });
|
|
|
//
|
|
|
//
|
|
|
CleartextStream.prototype._suck = function() { |
|
|
CryptoStream.prototype._blow = function() { |
|
|
var tmp, rv; |
|
|
var bytesRead; |
|
|
var havePending = this._pending.length > 0; |
|
|
var pool; |
|
|
|
|
|
var chunkBytes; |
|
|
|
|
|
var chunk; |
|
|
|
|
|
|
|
|
while (this._pending.length > 0) { |
|
|
do { |
|
|
tmp = this._pending.shift(); |
|
|
bytesRead = 0; |
|
|
|
|
|
chunkBytes = 0; |
|
|
|
|
|
pool = new Buffer(4096); // alloc every time?
|
|
|
|
|
|
pool.used = 0; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
try { |
|
|
try { |
|
|
debug('writng from clearIn'); |
|
|
chunkBytes = this._blower(pool, |
|
|
rv = this.pair._ssl.clearIn(tmp, 0, tmp.length); |
|
|
pool.used + bytesRead, |
|
|
|
|
|
pool.length - pool.used - bytesRead); |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
return this.pair._error(e); |
|
|
return this.pair._error(e); |
|
|
} |
|
|
} |
|
|
|
|
|
if (chunkBytes >= 0) { |
|
|
if (rv === 0) { |
|
|
bytesRead += chunkBytes; |
|
|
this._pending.unshift(tmp); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
assert(rv === tmp.length); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
} while ((chunkBytes > 0) && (pool.used + bytesRead < pool.length)); |
|
|
|
|
|
|
|
|
// If we've cleared all of incoming cleartext data, emit drain.
|
|
|
if (bytesRead > 0) { |
|
|
if (havePending && this._pending.length === 0) { |
|
|
chunk = pool.slice(0, bytesRead); |
|
|
debug('cleartext drain'); |
|
|
this.emit('data', chunk); |
|
|
this.emit('drain'); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
} while (bytesRead > 0 && this._writeState === true); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Move decrypted, clear data out into the application.
|
|
|
// Push in any clear data coming from the application.
|
|
|
// From the user's perspective this occurs as a 'data' event
|
|
|
// This arrives via some code like this:
|
|
|
// on the pair.cleartext.
|
|
|
//
|
|
|
CleartextStream.prototype._blow = function() { |
|
|
// pair.cleartext.write("hello world");
|
|
|
var self = this; |
|
|
//
|
|
|
self.pair._mover( |
|
|
// also
|
|
|
function(pool, offset, length) { |
|
|
//
|
|
|
debug('reading from clearOut'); |
|
|
|
|
|
return self.pair._ssl.clearOut(pool, offset, length); |
|
|
|
|
|
}, |
|
|
|
|
|
function(chunk) { |
|
|
|
|
|
self.emit('data', chunk); |
|
|
|
|
|
}, |
|
|
|
|
|
function() { |
|
|
|
|
|
return self._writeState === true; |
|
|
|
|
|
}); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function EncryptedStream (pair) { |
|
|
|
|
|
CryptoStream.call(this, pair); |
|
|
|
|
|
} |
|
|
|
|
|
util.inherits(EncryptedStream, CryptoStream); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Push in incoming encrypted data from the socket.
|
|
|
// Push in incoming encrypted data from the socket.
|
|
|
// This arrives via some code like this:
|
|
|
// This arrives via some code like this:
|
|
|
//
|
|
|
//
|
|
@ -167,15 +152,14 @@ util.inherits(EncryptedStream, CryptoStream); |
|
|
// pair.encrypted.write(d)
|
|
|
// pair.encrypted.write(d)
|
|
|
// });
|
|
|
// });
|
|
|
//
|
|
|
//
|
|
|
EncryptedStream.prototype._suck = function() { |
|
|
CryptoStream.prototype._suck = function() { |
|
|
var tmp, rv; |
|
|
var tmp, rv; |
|
|
var havePending = this._pending.length > 0; |
|
|
var havePending = this._pending.length > 0; |
|
|
while (this._pending.length > 0) { |
|
|
while (this._pending.length > 0) { |
|
|
tmp = this._pending.shift(); |
|
|
tmp = this._pending.shift(); |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
debug('writing from encIn'); |
|
|
rv = this._sucker(tmp); |
|
|
rv = this.pair._ssl.encIn(tmp, 0, tmp.length); |
|
|
|
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
return this.pair._error(e); |
|
|
return this.pair._error(e); |
|
|
} |
|
|
} |
|
@ -190,39 +174,48 @@ EncryptedStream.prototype._suck = function() { |
|
|
|
|
|
|
|
|
// If we've cleared all of incoming encrypted data, emit drain.
|
|
|
// If we've cleared all of incoming encrypted data, emit drain.
|
|
|
if (havePending && this._pending && this._pending.length === 0) { |
|
|
if (havePending && this._pending && this._pending.length === 0) { |
|
|
debug('encrypted drain'); |
|
|
debug('drain'); |
|
|
this.emit('drain'); |
|
|
this.emit('drain'); |
|
|
} |
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function CleartextStream (pair) { |
|
|
|
|
|
CryptoStream.call(this, pair); |
|
|
} |
|
|
} |
|
|
|
|
|
util.inherits(CleartextStream, CryptoStream); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Move encrypted data to the stream. From the user's perspective this
|
|
|
CleartextStream.prototype._sucker = function(b) { |
|
|
// occurs as a 'data' event on the pair.encrypted. Usually the application
|
|
|
debug('writng from clearIn'); |
|
|
// will have some code which pipes the stream to a socket:
|
|
|
return this.pair._ssl.clearIn(b, 0, b.length); |
|
|
//
|
|
|
}; |
|
|
// pair.encrypted.on('data', function (d) {
|
|
|
|
|
|
// socket.write(d);
|
|
|
|
|
|
// });
|
|
|
|
|
|
//
|
|
|
|
|
|
EncryptedStream.prototype._blow = function () { |
|
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
|
|
|
|
self.pair._mover( |
|
|
|
|
|
function(pool, offset, length) { |
|
|
CleartextStream.prototype._blower = function(pool, offset, length) { |
|
|
debug('reading from encOut'); |
|
|
debug('reading from clearOut'); |
|
|
if (!self.pair._ssl) return -1; |
|
|
return this.pair._ssl.clearOut(pool, offset, length); |
|
|
return self.pair._ssl.encOut(pool, offset, length); |
|
|
}; |
|
|
}, |
|
|
|
|
|
function(chunk) { |
|
|
|
|
|
self.emit('data', chunk); |
|
|
function EncryptedStream (pair) { |
|
|
}, |
|
|
CryptoStream.call(this, pair); |
|
|
function() { |
|
|
} |
|
|
if (!self.pair._ssl) return false; |
|
|
util.inherits(EncryptedStream, CryptoStream); |
|
|
return self._writeState === true; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
EncryptedStream.prototype._sucker = function(b) { |
|
|
|
|
|
debug('writing from encIn'); |
|
|
|
|
|
return this.pair._ssl.encIn(b, 0, b.length); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EncryptedStream.prototype._blower = function(pool, offset, length) { |
|
|
|
|
|
debug('reading from encOut'); |
|
|
|
|
|
if (!this.pair._ssl) return -1; |
|
|
|
|
|
return this.pair._ssl.encOut(pool, offset, length); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Provides a pair of streams to do encrypted communication. |
|
|
* Provides a pair of streams to do encrypted communication. |
|
@ -304,37 +297,6 @@ exports.createSecurePair = function(credentials, |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SecurePair.prototype._mover = function(reader, writer, checker) { |
|
|
|
|
|
var bytesRead; |
|
|
|
|
|
var pool; |
|
|
|
|
|
var chunkBytes; |
|
|
|
|
|
var chunk; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
|
bytesRead = 0; |
|
|
|
|
|
chunkBytes = 0; |
|
|
|
|
|
pool = new Buffer(4096); // alloc every time?
|
|
|
|
|
|
pool.used = 0; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
|
try { |
|
|
|
|
|
chunkBytes = reader(pool, |
|
|
|
|
|
pool.used + bytesRead, |
|
|
|
|
|
pool.length - pool.used - bytesRead); |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
return this._error(e); |
|
|
|
|
|
} |
|
|
|
|
|
if (chunkBytes >= 0) { |
|
|
|
|
|
bytesRead += chunkBytes; |
|
|
|
|
|
} |
|
|
|
|
|
} while ((chunkBytes > 0) && (pool.used + bytesRead < pool.length)); |
|
|
|
|
|
|
|
|
|
|
|
if (bytesRead > 0) { |
|
|
|
|
|
chunk = pool.slice(0, bytesRead); |
|
|
|
|
|
writer(chunk); |
|
|
|
|
|
} |
|
|
|
|
|
} while (bytesRead > 0 && checker()); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|