<commit_before>'use strict';

var debug = require('debug')('amqp10:sasl'),
    Builder = require('buffer-builder'),

    constants = require('./constants'),
    frames = require('./frames'),
    errors = require('./errors'),
    u = require('./utilities'),

    Connection = require('./connection');

var saslMechanisms = {
  PLAIN: 'PLAIN',
  ANONYMOUS: 'ANONYMOUS',
  NONE: 'NONE'
};

/**
 * Currently, only supports SASL ANONYMOUS or PLAIN
 *
 * @constructor
 */
function Sasl(mechanism) {
  if (mechanism && !u.includes(saslMechanisms, mechanism)) {
    throw new errors.NotImplementedError(
      'Only SASL PLAIN and ANONYMOUS are supported.');
  }
  this.mechanism = mechanism;
  this.receivedHeader = false;
}

Sasl.Mechanism = saslMechanisms;

Sasl.prototype.negotiate = function(connection, credentials, done) {
  this.connection = connection;
  this.credentials = credentials;
  if (this.credentials.user && this.credentials.pass && !this.mechanism) {
    this.mechanism = Sasl.Mechanism.PLAIN;
  }
  this.callback = done;
  var self = this;
  this._processFrameEH = function(frame) { self._processFrame(frame); };
  this.connection.on(Connection.FrameReceived, this._processFrameEH);
  this._sendHeader();
};

Sasl.prototype._sendHeader = function() {
  this.connection.sendHeader(constants.saslVersion);
};

Sasl.prototype.headerReceived = function(header) {
  debug('Server SASL Version: ' + header.toString('hex') + ' vs ' + constants.saslVersion.toString('hex'));
  if (u.bufferEquals(header, constants.saslVersion)) {
    this.receivedHeader = true;
    // Wait for mechanisms
  } else {
    this.callback(new errors.MalformedHeaderError('Invalid SASL Header ' + header.toString('hex')));
  }
};

Sasl.prototype._processFrame = function(frame) {
  if (frame instanceof frames.SaslMechanismsFrame) {
    var buf = new Builder();
    var mechanism = this.mechanism;
    if (!u.includes(frame.saslServerMechanisms, mechanism)) {
      throw new errors.AuthenticationError(
        'SASL ' + mechanism + ' not supported by remote.');
    }
    if (mechanism === Sasl.Mechanism.PLAIN) {
      debug('Sending ' + this.credentials.user + ':' + this.credentials.pass);
      buf.appendUInt8(0); // <null>
      buf.appendString(this.credentials.user);
      buf.appendUInt8(0); // <null>
      buf.appendString(this.credentials.pass);
    } else if (mechanism === Sasl.Mechanism.ANONYMOUS) {
      if (this.credentials.user && this.credentials.pass) {
        console.warn(
            'Sasl ANONYMOUS requested, but credentials provided in endpoint URI');
      }
      buf.appendUInt8(0); // <null>
    } else {
      throw new errors.NotImplementedError(
          'Only SASL PLAIN and ANONYMOUS are supported.');
    }
    var initFrame = new frames.SaslInitFrame({
      mechanism: mechanism,
      initialResponse: buf.get()
    });

    if (!!this._remoteHostname) initFrame.hostname = this._remoteHostname;
    this.connection.sendFrame(initFrame);
  } else if (frame instanceof frames.SaslChallengeFrame) {
    var responseFrame = new frames.SaslResponseFrame({});
    this.connection.sendFrame(responseFrame);
  } else if (frame instanceof frames.SaslOutcomeFrame) {
    if (frame.code === constants.saslOutcomes.ok) {
      this.callback();
    } else {
      this.callback(new errors.AuthenticationError('SASL Failed: ' + frame.code + ': ' + frame.details));
    }
  }
};

// @todo: Methods for sending init, receiving challenge, sending response, receiving outcome.

module.exports = Sasl;
<commit_msg>fix(sasl): Make private saslMechanisms singular<commit_after>'use strict';

var debug = require('debug')('amqp10:sasl'),
    Builder = require('buffer-builder'),

    constants = require('./constants'),
    frames = require('./frames'),
    errors = require('./errors'),
    u = require('./utilities'),

    Connection = require('./connection');

var saslMechanism = {
  PLAIN: 'PLAIN',
  ANONYMOUS: 'ANONYMOUS',
  NONE: 'NONE'
};

/**
 * Currently, only supports SASL ANONYMOUS or PLAIN
 *
 * @constructor
 */
function Sasl(mechanism) {
  if (mechanism && !u.includes(saslMechanism, mechanism)) {
    throw new errors.NotImplementedError(
      'Only SASL PLAIN and ANONYMOUS are supported.');
  }
  this.mechanism = mechanism;
  this.receivedHeader = false;
}

Sasl.Mechanism = saslMechanism;

Sasl.prototype.negotiate = function(connection, credentials, done) {
  this.connection = connection;
  this.credentials = credentials;
  if (this.credentials.user && this.credentials.pass && !this.mechanism) {
    this.mechanism = Sasl.Mechanism.PLAIN;
  }
  this.callback = done;
  var self = this;
  this._processFrameEH = function(frame) { self._processFrame(frame); };
  this.connection.on(Connection.FrameReceived, this._processFrameEH);
  this._sendHeader();
};

Sasl.prototype._sendHeader = function() {
  this.connection.sendHeader(constants.saslVersion);
};

Sasl.prototype.headerReceived = function(header) {
  debug('Server SASL Version: ' + header.toString('hex') + ' vs ' + constants.saslVersion.toString('hex'));
  if (u.bufferEquals(header, constants.saslVersion)) {
    this.receivedHeader = true;
    // Wait for mechanisms
  } else {
    this.callback(new errors.MalformedHeaderError('Invalid SASL Header ' + header.toString('hex')));
  }
};

Sasl.prototype._processFrame = function(frame) {
  if (frame instanceof frames.SaslMechanismsFrame) {
    var buf = new Builder();
    var mechanism = this.mechanism;
    if (!u.includes(frame.saslServerMechanisms, mechanism)) {
      throw new errors.AuthenticationError(
        'SASL ' + mechanism + ' not supported by remote.');
    }
    if (mechanism === Sasl.Mechanism.PLAIN) {
      debug('Sending ' + this.credentials.user + ':' + this.credentials.pass);
      buf.appendUInt8(0); // <null>
      buf.appendString(this.credentials.user);
      buf.appendUInt8(0); // <null>
      buf.appendString(this.credentials.pass);
    } else if (mechanism === Sasl.Mechanism.ANONYMOUS) {
      if (this.credentials.user && this.credentials.pass) {
        console.warn(
            'Sasl ANONYMOUS requested, but credentials provided in endpoint URI');
      }
      buf.appendUInt8(0); // <null>
    } else {
      throw new errors.NotImplementedError(
          'Only SASL PLAIN and ANONYMOUS are supported.');
    }
    var initFrame = new frames.SaslInitFrame({
      mechanism: mechanism,
      initialResponse: buf.get()
    });

    if (!!this._remoteHostname) initFrame.hostname = this._remoteHostname;
    this.connection.sendFrame(initFrame);
  } else if (frame instanceof frames.SaslChallengeFrame) {
    var responseFrame = new frames.SaslResponseFrame({});
    this.connection.sendFrame(responseFrame);
  } else if (frame instanceof frames.SaslOutcomeFrame) {
    if (frame.code === constants.saslOutcomes.ok) {
      this.callback();
    } else {
      this.callback(new errors.AuthenticationError('SASL Failed: ' + frame.code + ': ' + frame.details));
    }
  }
};

// @todo: Methods for sending init, receiving challenge, sending response, receiving outcome.

module.exports = Sasl;

{'fraction_non_alphanumeric': 0.13829636954372088, 'fraction_numerical': 0.0022602062438197485, 'mean_word_length': 3.642622950819672, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2673107', 'n_tokens_mistral': 2283, 'n_tokens_neox': 2240, 'n_words': 450}