Esempio n. 1
0
// Server side times how long a handshake is taking to protect against slow
// handshakes being used for DoS.
function onhandshakestart(now) {
  debug('server onhandshakestart');

  const { lastHandshakeTime } = this;
  assert(now >= lastHandshakeTime,
         `now (${now}) < lastHandshakeTime (${lastHandshakeTime})`);

  this.lastHandshakeTime = now;

  // If this is the first handshake we can skip the rest of the checks.
  if (lastHandshakeTime === 0)
    return;

  if ((now - lastHandshakeTime) >= tls.CLIENT_RENEG_WINDOW * 1000)
    this.handshakes = 1;
  else
    this.handshakes++;

  const owner = this[owner_symbol];

  assert(owner._tlsOptions.isServer);

  if (this.handshakes > tls.CLIENT_RENEG_LIMIT) {
    owner._emitTLSError(new ERR_TLS_SESSION_ATTACK());
    return;
  }

  if (owner[kDisableRenegotiation])
    owner._emitTLSError(new ERR_TLS_RENEGOTIATION_DISABLED());
}
Esempio n. 2
0
TLSSocket.prototype._wrapHandle = function(wrap) {
  var handle;

  if (wrap)
    handle = wrap._handle;

  const options = this._tlsOptions;
  if (!handle) {
    handle = options.pipe ?
      new Pipe(PipeConstants.SOCKET) :
      new TCP(TCPConstants.SOCKET);
    handle[owner_symbol] = this;
  }

  // Wrap socket's handle
  const context = options.secureContext ||
                  options.credentials ||
                  tls.createSecureContext(options);
  assert(handle.isStreamBase, 'handle must be a StreamBase');
  assert(context.context instanceof NativeSecureContext,
         'context.context must be a NativeSecureContext');
  const res = tls_wrap.wrap(handle, context.context, !!options.isServer);
  res._parent = handle;  // C++ "wrap" object: TCPWrap, JSStream, ...
  res._parentWrap = wrap;  // JS object: net.Socket, JSStreamSocket, ...
  res._secureContext = context;
  res.reading = handle.reading;
  this[kRes] = res;
  defineHandleReading(this, handle);

  this.on('close', onSocketCloseDestroySSL);

  return res;
};
Esempio n. 3
0
// The base class for all Zlib-style streams.
function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) {
  var chunkSize = Z_DEFAULT_CHUNK;
  // The ZlibBase class is not exported to user land, the mode should only be
  // passed in by us.
  assert(typeof mode === 'number');
  assert(mode >= DEFLATE && mode <= BROTLI_ENCODE);

  if (opts) {
    chunkSize = opts.chunkSize;
    if (!checkFiniteNumber(chunkSize, 'options.chunkSize')) {
      chunkSize = Z_DEFAULT_CHUNK;
    } else if (chunkSize < Z_MIN_CHUNK) {
      throw new ERR_OUT_OF_RANGE('options.chunkSize',
                                 `>= ${Z_MIN_CHUNK}`, chunkSize);
    }

    flush = checkRangesOrGetDefault(
      opts.flush, 'options.flush',
      Z_NO_FLUSH, Z_BLOCK, flush);

    finishFlush = checkRangesOrGetDefault(
      opts.finishFlush, 'options.finishFlush',
      Z_NO_FLUSH, Z_BLOCK, finishFlush);

    if (opts.encoding || opts.objectMode || opts.writableObjectMode) {
      opts = { ...opts };
      opts.encoding = null;
      opts.objectMode = false;
      opts.writableObjectMode = false;
    }
  }

  Transform.call(this, opts);
  this._hadError = false;
  this.bytesWritten = 0;
  this._handle = handle;
  handle[owner_symbol] = this;
  // Used by processCallback() and zlibOnError()
  handle.onerror = zlibOnError;
  this._outBuffer = Buffer.allocUnsafe(chunkSize);
  this._outOffset = 0;

  this._chunkSize = chunkSize;
  this._defaultFlushFlag = flush;
  this._finishFlushFlag = finishFlush;
  this._nextFlush = -1;
  this._defaultFullFlushFlag = fullFlush;
  this.once('end', this.close);
  this._info = opts && opts.info;
}
Esempio n. 4
0
function setupChildProcessIpcChannel() {
  if (process.env.NODE_CHANNEL_FD) {
    const assert = require('internal/assert');

    const fd = parseInt(process.env.NODE_CHANNEL_FD, 10);
    assert(fd >= 0);

    // Make sure it's not accidentally inherited by child processes.
    delete process.env.NODE_CHANNEL_FD;

    require('child_process')._forkChild(fd);
    assert(process.send);
  }
}
Esempio n. 5
0
function Brotli(opts, mode) {
  assert(mode === BROTLI_DECODE || mode === BROTLI_ENCODE);

  brotliInitParamsArray.fill(-1);
  if (opts && opts.params) {
    for (const origKey of Object.keys(opts.params)) {
      const key = +origKey;
      if (Number.isNaN(key) || key < 0 || key > kMaxBrotliParam ||
          (brotliInitParamsArray[key] | 0) !== -1) {
        throw new ERR_BROTLI_INVALID_PARAM(origKey);
      }

      const value = opts.params[origKey];
      if (typeof value !== 'number' && typeof value !== 'boolean') {
        throw new ERR_INVALID_ARG_TYPE('options.params[key]',
                                       'number', opts.params[origKey]);
      }
      brotliInitParamsArray[key] = value;
    }
  }

  const handle = mode === BROTLI_DECODE ?
    new binding.BrotliDecoder(mode) : new binding.BrotliEncoder(mode);

  this._writeState = new Uint32Array(2);
  if (!handle.init(brotliInitParamsArray,
                   this._writeState,
                   processCallback)) {
    throw new ERR_ZLIB_INITIALIZATION_FAILED();
  }

  ZlibBase.call(this, opts, mode, handle, brotliDefaultOpts);
}
Esempio n. 6
0
// Look up the keys of the object.
function getKeys(value, showHidden) {
  let keys;
  const symbols = Object.getOwnPropertySymbols(value);
  if (showHidden) {
    keys = Object.getOwnPropertyNames(value);
    if (symbols.length !== 0)
      keys.push(...symbols);
  } else {
    // This might throw if `value` is a Module Namespace Object from an
    // unevaluated module, but we don't want to perform the actual type
    // check because it's expensive.
    // TODO(devsnek): track https://github.com/tc39/ecma262/issues/1209
    // and modify this logic as needed.
    try {
      keys = Object.keys(value);
    } catch (err) {
      assert(isNativeError(err) && err.name === 'ReferenceError' &&
             isModuleNamespaceObject(value));
      keys = Object.getOwnPropertyNames(value);
    }
    if (symbols.length !== 0) {
      keys.push(...symbols.filter((key) => propertyIsEnumerable(value, key)));
    }
  }
  return keys;
}
Esempio n. 7
0
Module.prototype.load = function(filename) {
  debug('load %j for module %j', filename, this.id);

  assert(!this.loaded);
  this.filename = filename;
  this.paths = Module._nodeModulePaths(path.dirname(filename));

  const extension = findLongestRegisteredExtension(filename);
  Module._extensions[extension](this, filename);
  this.loaded = true;

  if (experimentalModules) {
    const ESMLoader = asyncESM.ESMLoader;
    const url = `${pathToFileURL(filename)}`;
    const module = ESMLoader.moduleMap.get(url);
    // Create module entry at load time to snapshot exports correctly
    const exports = this.exports;
    if (module !== undefined) { // Called from cjs translator
      module.reflect.onReady((reflect) => {
        reflect.exports.default.set(exports);
      });
    } else { // preemptively cache
      ESMLoader.moduleMap.set(
        url,
        new ModuleJob(ESMLoader, url, async () => {
          return createDynamicModule(
            ['default'], url, (reflect) => {
              reflect.exports.default.set(exports);
            });
        })
      );
    }
  }
};
Esempio n. 8
0
function getDecoder(decoder, encoding) {
  encoding = normalizeEncoding(encoding);
  if (StringDecoder === undefined)
    StringDecoder = require('string_decoder').StringDecoder;
  decoder = decoder || new StringDecoder(encoding);
  assert(decoder.encoding === encoding, 'Cannot change encoding');
  return decoder;
}
Esempio n. 9
0
// This callback is used by `.params()` to wait until a full flush happened
// before adjusting the parameters. In particular, the call to the native
// `params()` function should not happen while a write is currently in progress
// on the threadpool.
function paramsAfterFlushCallback(level, strategy, callback) {
  assert(this._handle, 'zlib binding closed');
  this._handle.params(level, strategy);
  if (!this._hadError) {
    this._level = level;
    this._strategy = strategy;
    if (callback) callback();
  }
}
Esempio n. 10
0
 _read(nread) {
   const state = this[kState];
   assert(!state.closed);
   if (!state.didRead) {
     state.didRead = true;
     this[kStream].on('data', onStreamData);
   } else {
     process.nextTick(resumeStream, this[kStream]);
   }
 }
Esempio n. 11
0
function onhandshakedone() {
  debug('server onhandshakedone');

  const owner = this[owner_symbol];
  assert(owner._tlsOptions.isServer);

  // `newSession` callback wasn't called yet
  if (owner._newSessionPending) {
    owner._securePending = true;
    return;
  }

  owner._finishInit();
}
Esempio n. 12
0
// Round-robin. Master distributes handles across workers.
function rr(message, indexesKey, cb) {
  if (message.errno)
    return cb(message.errno, null);

  var key = message.key;

  function listen(backlog) {
    // TODO(bnoordhuis) Send a message to the master that tells it to
    // update the backlog size. The actual backlog should probably be
    // the largest requested size by any worker.
    return 0;
  }

  function close() {
    // lib/net.js treats server._handle.close() as effectively synchronous.
    // That means there is a time window between the call to close() and
    // the ack by the master process in which we can still receive handles.
    // onconnection() below handles that by sending those handles back to
    // the master.
    if (key === undefined)
      return;

    send({ act: 'close', key });
    handles.delete(key);
    indexes.delete(indexesKey);
    key = undefined;
  }

  function getsockname(out) {
    if (key)
      Object.assign(out, message.sockname);

    return 0;
  }

  // Faux handle. Mimics a TCPWrap with just enough fidelity to get away
  // with it. Fools net.Server into thinking that it's backed by a real
  // handle. Use a noop function for ref() and unref() because the control
  // channel is going to keep the worker alive anyway.
  const handle = { close, listen, ref: noop, unref: noop };

  if (message.sockname) {
    handle.getsockname = getsockname;  // TCP handles only.
  }

  assert(handles.has(key) === false);
  handles.set(key, handle);
  cb(0, handle);
}
Esempio n. 13
0
// Shared listen socket.
function shared(message, handle, indexesKey, cb) {
  const key = message.key;
  // Monkey-patch the close() method so we can keep track of when it's
  // closed. Avoids resource leaks when the handle is short-lived.
  const close = handle.close;

  handle.close = function() {
    send({ act: 'close', key });
    handles.delete(key);
    indexes.delete(indexesKey);
    return close.apply(this, arguments);
  }.bind(handle);
  assert(handles.has(key) === false);
  handles.set(key, handle);
  cb(message.errno, handle);
}
Esempio n. 14
0
    const link = async () => {
      ({ module: this.module,
         reflect: this.reflect } = await this.modulePromise);
      assert(this.module instanceof ModuleWrap);

      const dependencyJobs = [];
      const promises = this.module.link(async (specifier) => {
        const jobPromise = this.loader.getModuleJob(specifier, url);
        dependencyJobs.push(jobPromise);
        return (await (await jobPromise).modulePromise).module;
      });

      if (promises !== undefined)
        await SafePromise.all(promises);

      return SafePromise.all(dependencyJobs);
    };
Esempio n. 15
0
function processChunk(self, chunk, flushFlag, cb) {
  const handle = self._handle;
  assert(handle, 'zlib binding closed');

  handle.buffer = chunk;
  handle.cb = cb;
  handle.availOutBefore = self._chunkSize - self._outOffset;
  handle.availInBefore = chunk.byteLength;
  handle.inOff = 0;
  handle.flushFlag = flushFlag;

  handle.write(flushFlag,
               chunk, // in
               0, // in_off
               handle.availInBefore, // in_len
               self._outBuffer, // out
               self._outOffset, // out_off
               handle.availOutBefore); // out_len
}
Esempio n. 16
0
OutgoingMessage.prototype._finish = function _finish() {
  assert(this.connection);
  this.emit('prefinish');
};
Esempio n. 17
0
assert.throws(() => { internalAssert(false, 'fhqwhgads'); },
Esempio n. 18
0
assert.throws(() => { internalAssert(false); }, assert.AssertionError);
Esempio n. 19
0
// Flags: --expose-internals
'use strict';

require('../common');

const assert = require('assert');
const internalAssert = require('internal/assert');

// Should not throw.
internalAssert(true);
internalAssert(true, 'fhqwhgads');

assert.throws(() => { internalAssert(false); }, assert.AssertionError);
assert.throws(() => { internalAssert(false, 'fhqwhgads'); },
              { code: 'ERR_ASSERTION', message: 'fhqwhgads' });
assert.throws(() => { internalAssert.fail('fhqwhgads'); },
              { code: 'ERR_ASSERTION', message: 'fhqwhgads' });
Esempio n. 20
0
'use strict';

// Flags: --expose-internals
require('../common');

const assert = require('internal/assert');
assert(false);
Esempio n. 21
0
TLSSocket.prototype._init = function(socket, wrap) {
  const options = this._tlsOptions;
  const ssl = this._handle;
  this.server = options.server;

  debug('%s _init',
        options.isServer ? 'server' : 'client',
        'handle?', !!ssl
  );

  // Clients (!isServer) always request a cert, servers request a client cert
  // only on explicit configuration.
  const requestCert = !!options.requestCert || !options.isServer;
  const rejectUnauthorized = !!options.rejectUnauthorized;

  this._requestCert = requestCert;
  this._rejectUnauthorized = rejectUnauthorized;
  if (requestCert || rejectUnauthorized)
    ssl.setVerifyMode(requestCert, rejectUnauthorized);

  if (options.isServer) {
    ssl.onhandshakestart = onhandshakestart;
    ssl.onhandshakedone = onhandshakedone;
    ssl.onclienthello = loadSession;
    ssl.oncertcb = loadSNI;
    ssl.onnewsession = onnewsession;
    ssl.lastHandshakeTime = 0;
    ssl.handshakes = 0;

    if (this.server) {
      if (this.server.listenerCount('resumeSession') > 0 ||
          this.server.listenerCount('newSession') > 0) {
        // Also starts the client hello parser as a side effect.
        ssl.enableSessionCallbacks();
      }
      if (this.server.listenerCount('OCSPRequest') > 0)
        ssl.enableCertCb();
    }
  } else {
    ssl.onhandshakestart = noop;
    ssl.onhandshakedone = () => {
      debug('client onhandshakedone');
      this._finishInit();
    };
    ssl.onocspresponse = onocspresponse;

    if (options.session)
      ssl.setSession(options.session);

    ssl.onnewsession = onnewsessionclient;

    // Only call .onnewsession if there is a session listener.
    this.on('newListener', newListener);

    function newListener(event) {
      if (event !== 'session')
        return;

      ssl.enableSessionCallbacks();

      // Remover this listener since its no longer needed.
      this.removeListener('newListener', newListener);
    }
  }

  ssl.onerror = onerror;

  // If custom SNICallback was given, or if
  // there're SNI contexts to perform match against -
  // set `.onsniselect` callback.
  if (options.isServer &&
      options.SNICallback &&
      (options.SNICallback !== SNICallback ||
       (options.server && options.server._contexts.length))) {
    assert(typeof options.SNICallback === 'function');
    this._SNICallback = options.SNICallback;
    ssl.enableCertCb();
  }

  if (options.ALPNProtocols) {
    // Keep reference in secureContext not to be GC-ed
    ssl._secureContext.alpnBuffer = options.ALPNProtocols;
    ssl.setALPNProtocols(ssl._secureContext.alpnBuffer);
  }

  if (options.handshakeTimeout > 0)
    this.setTimeout(options.handshakeTimeout, this._handleTimeout);

  if (socket instanceof net.Socket) {
    this._parent = socket;

    // To prevent assertion in afterConnect() and properly kick off readStart
    this.connecting = socket.connecting || !socket._handle;
    socket.once('connect', () => {
      this.connecting = false;
      this.emit('connect');
    });
  }

  // Assume `tls.connect()`
  if (wrap) {
    wrap.on('error', (err) => this._emitTLSError(err));
  } else {
    assert(!socket);
    this.connecting = true;
  }
};
Esempio n. 22
0
ZlibBase.prototype.reset = function() {
  if (!this._handle)
    assert(false, 'zlib binding closed');
  return this._handle.reset();
};
Esempio n. 23
0
exports.connect = function connect(...args) {
  args = normalizeConnectArgs(args);
  var options = args[0];
  const cb = args[1];
  const allowUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0';

  if (allowUnauthorized && warnOnAllowUnauthorized) {
    warnOnAllowUnauthorized = false;
    process.emitWarning('Setting the NODE_TLS_REJECT_UNAUTHORIZED ' +
                        'environment variable to \'0\' makes TLS connections ' +
                        'and HTTPS requests insecure by disabling ' +
                        'certificate verification.');
  }

  options = {
    rejectUnauthorized: !allowUnauthorized,
    ciphers: tls.DEFAULT_CIPHERS,
    checkServerIdentity: tls.checkServerIdentity,
    minDHSize: 1024,
    ...options
  };

  if (!options.keepAlive)
    options.singleUse = true;

  assert(typeof options.checkServerIdentity === 'function');
  assert(typeof options.minDHSize === 'number',
         'options.minDHSize is not a number: ' + options.minDHSize);
  assert(options.minDHSize > 0,
         'options.minDHSize is not a positive number: ' +
         options.minDHSize);

  const context = options.secureContext || tls.createSecureContext(options);

  const tlssock = new TLSSocket(options.socket, {
    pipe: !!options.path,
    secureContext: context,
    isServer: false,
    requestCert: true,
    rejectUnauthorized: options.rejectUnauthorized !== false,
    session: options.session,
    ALPNProtocols: options.ALPNProtocols,
    requestOCSP: options.requestOCSP
  });

  tlssock[kConnectOptions] = options;

  if (cb)
    tlssock.once('secureConnect', cb);

  if (!options.socket) {
    // If user provided the socket, its their responsibility to manage its
    // connectivity. If we created one internally, we connect it.
    const connectOpt = {
      path: options.path,
      port: options.port,
      host: options.host,
      family: options.family,
      localAddress: options.localAddress,
      localPort: options.localPort,
      lookup: options.lookup
    };

    if (options.timeout) {
      tlssock.setTimeout(options.timeout);
    }

    tlssock.connect(connectOpt, tlssock._start);
  }

  tlssock._releaseControl();

  if (options.session)
    tlssock.setSession(options.session);

  if (options.servername) {
    if (!ipServernameWarned && net.isIP(options.servername)) {
      process.emitWarning(
        'Setting the TLS ServerName to an IP address is not permitted by ' +
        'RFC 6066. This will be ignored in a future version.',
        'DeprecationWarning',
        'DEP0123'
      );
      ipServernameWarned = true;
    }
    tlssock.setServername(options.servername);
  }

  if (options.socket)
    tlssock._start();

  tlssock.on('secure', onConnectSecure);
  tlssock.once('end', onConnectEnd);

  return tlssock;
};
Esempio n. 24
0
function processChunkSync(self, chunk, flushFlag) {
  var availInBefore = chunk.byteLength;
  var availOutBefore = self._chunkSize - self._outOffset;
  var inOff = 0;
  var availOutAfter;
  var availInAfter;

  var buffers = null;
  var nread = 0;
  var inputRead = 0;
  const state = self._writeState;
  const handle = self._handle;
  var buffer = self._outBuffer;
  var offset = self._outOffset;
  const chunkSize = self._chunkSize;

  var error;
  self.on('error', function onError(er) {
    error = er;
  });

  while (true) {
    handle.writeSync(flushFlag,
                     chunk, // in
                     inOff, // in_off
                     availInBefore, // in_len
                     buffer, // out
                     offset, // out_off
                     availOutBefore); // out_len
    if (error)
      throw error;

    availOutAfter = state[0];
    availInAfter = state[1];

    var inDelta = (availInBefore - availInAfter);
    inputRead += inDelta;

    var have = availOutBefore - availOutAfter;
    if (have > 0) {
      var out = buffer.slice(offset, offset + have);
      offset += have;
      if (!buffers)
        buffers = [out];
      else
        buffers.push(out);
      nread += out.byteLength;
    } else {
      assert(have === 0, 'have should not go down');
    }

    // Exhausted the output buffer, or used all the input create a new one.
    if (availOutAfter === 0 || offset >= chunkSize) {
      availOutBefore = chunkSize;
      offset = 0;
      buffer = Buffer.allocUnsafe(chunkSize);
    }

    if (availOutAfter === 0) {
      // Not actually done. Need to reprocess.
      // Also, update the availInBefore to the availInAfter value,
      // so that if we have to hit it a third (fourth, etc.) time,
      // it'll have the correct byte counts.
      inOff += inDelta;
      availInBefore = availInAfter;
    } else {
      break;
    }
  }

  self.bytesWritten = inputRead;
  _close(self);

  if (nread >= kMaxLength) {
    throw new ERR_BUFFER_TOO_LARGE();
  }

  if (nread === 0)
    return Buffer.alloc(0);

  return (buffers.length === 1 ? buffers[0] : Buffer.concat(buffers, nread));
}
Esempio n. 25
0
function processCallback() {
  // This callback's context (`this`) is the `_handle` (ZCtx) object. It is
  // important to null out the values once they are no longer needed since
  // `_handle` can stay in memory long after the buffer is needed.
  const handle = this;
  const self = this[owner_symbol];
  const state = self._writeState;

  if (self._hadError) {
    this.buffer = null;
    return;
  }

  if (self.destroyed) {
    this.buffer = null;
    return;
  }

  const availOutAfter = state[0];
  const availInAfter = state[1];

  const inDelta = handle.availInBefore - availInAfter;
  self.bytesWritten += inDelta;

  const have = handle.availOutBefore - availOutAfter;
  if (have > 0) {
    var out = self._outBuffer.slice(self._outOffset, self._outOffset + have);
    self._outOffset += have;
    self.push(out);
  } else {
    assert(have === 0, 'have should not go down');
  }

  if (self.destroyed) {
    return;
  }

  // Exhausted the output buffer, or used all the input create a new one.
  if (availOutAfter === 0 || self._outOffset >= self._chunkSize) {
    handle.availOutBefore = self._chunkSize;
    self._outOffset = 0;
    self._outBuffer = Buffer.allocUnsafe(self._chunkSize);
  }

  if (availOutAfter === 0) {
    // Not actually done. Need to reprocess.
    // Also, update the availInBefore to the availInAfter value,
    // so that if we have to hit it a third (fourth, etc.) time,
    // it'll have the correct byte counts.
    handle.inOff += inDelta;
    handle.availInBefore = availInAfter;

    this.write(handle.flushFlag,
               this.buffer, // in
               handle.inOff, // in_off
               handle.availInBefore, // in_len
               self._outBuffer, // out
               self._outOffset, // out_off
               self._chunkSize); // out_len
    return;
  }

  if (availInAfter > 0) {
    // If we have more input that should be written, but we also have output
    // space available, that means that the compression library was not
    // interested in receiving more data, and in particular that the input
    // stream has ended early.
    // This applies to streams where we don't check data past the end of
    // what was consumed; that is, everything except Gunzip/Unzip.
    self.push(null);
  }

  // Finished with the chunk.
  this.buffer = null;
  this.cb();
}