<commit_before>var debug = require('debug')('zmq-zap:zap'),
	net = require('net');

var ZAP = function(options) {
	this._options = options || {};
	this._mechanisms = {};
}

ZAP.prototype._captureReturnPath = function(data) {
	var returnPath = [];
	
	var frame = data.shift();
	while (frame.length != 0) {
		returnPath.push(frame);
		frame = data.shift();
	}
	returnPath.push(frame);
	
	return returnPath;
}

ZAP.prototype._parseRequestData = function(data) {
	var req;
	if (data && (data.length >= 6)) {
		req = {
			version: new Buffer(data.shift()).toString('utf8'),
			requestId: new Buffer(data.shift()).toString('utf8'),
			domain: new Buffer(data.shift()).toString('utf8'),
			address: new Buffer(data.shift()).toString('utf8'),
			identity: new Buffer(data.shift()).toString('utf8'),
			mechanism: new Buffer(data.shift()).toString('utf8'),
			credentials: data.slice(0)
		};
	}
	return req;
}

ZAP.prototype._validateRequest = function(req, mech) {
	if (req.version != "1.0") return false;
	if (!req.requestId) return false;
	if (!net.isIP(req.address)) return false;
	
	if (mech && (typeof mech.validate === 'function')) return mech.validate(req);
	else return true;
}

ZAP.prototype._generateResponse = function(req, returnPath, statusCode, message, userId, metadata) {
	if (!message) {
		switch (statusCode) {
			case 200:
				message = "OK";
				break;
			case 300:
				message = "ERR";
				break;
			case 400:
				message = "AUTHFAIL";
				break;
			case 500:
				message = "INTERR";
				break;
		}
	}
	
	debug('Authentication response: %s', JSON.stringify({
		version: req.version,
		requestId: req.requestId,
		statusCode: statusCode,
		message: message,
		userId: userId,
		metadata: metadata
	}, true, 2));
	
	return (returnPath || []).splice(0).concat([
		new Buffer(req.version, 'utf8'),
		new Buffer(req.requestId, 'utf8'),
		new Buffer(statusCode.toString(), 'utf8'),
		(message ? new Buffer(message, 'utf8') : new Buffer(0)),
		(((statusCode == 200) && userId) ? new Buffer(userId, 'utf8') : new Buffer(0)),
		(((statusCode == 200) && (metadata)) ? metadata : new Buffer(0))
	]);
}

ZAP.prototype.use = function(mechanism) {
	if (!mechanism) throw new Error('Invalid mechanism');
	if ((typeof mechanism.name !== 'string') || !mechanism.name.length) throw new Error("Invalid mechanism name");
	if (typeof mechanism.authenticate !== 'function') throw new Error('Invalid mechanism authenticate handler');
	
	this._mechanisms[mechanism.name] = mechanism;
}

ZAP.prototype.authenticate = function(data, callback) {
	var data = Array.prototype.slice.call(data); // This forces data to be an array (for when 'arguments' is passed in directly)
	
	var returnPath = this._captureReturnPath(data),
		req = this._parseRequestData(data),
		mech = this._mechanisms[req.mechanism];
	
	if (req && this._validateRequest(req, mech)) {
		debug('Authentication request: %s', JSON.stringify(req, true, 2));
		<commit_msg>_generateResponse should return undefined when it doesn't have enough data to actually generate a response<commit_after>var debug = require('debug')('zmq-zap:zap'),
	net = require('net');

var ZAP = function(options) {
	this._options = options || {};
	this._mechanisms = {};
}

ZAP.prototype._captureReturnPath = function(data) {
	var returnPath = [];
	
	var frame = data.shift();
	while (frame.length != 0) {
		returnPath.push(frame);
		frame = data.shift();
	}
	returnPath.push(frame);
	
	return returnPath;
}

ZAP.prototype._parseRequestData = function(data) {
	var req;
	if (data && (data.length >= 6)) {
		req = {
			version: new Buffer(data.shift()).toString('utf8'),
			requestId: new Buffer(data.shift()).toString('utf8'),
			domain: new Buffer(data.shift()).toString('utf8'),
			address: new Buffer(data.shift()).toString('utf8'),
			identity: new Buffer(data.shift()).toString('utf8'),
			mechanism: new Buffer(data.shift()).toString('utf8'),
			credentials: data.slice(0)
		};
	}
	return req;
}

ZAP.prototype._validateRequest = function(req, mech) {
	if (req.version != "1.0") return false;
	if (!req.requestId) return false;
	if (!net.isIP(req.address)) return false;
	
	if (mech && (typeof mech.validate === 'function')) return mech.validate(req);
	else return true;
}

ZAP.prototype._generateResponse = function(req, returnPath, statusCode, message, userId, metadata) {
	if (!message && statusCode) {
		switch (statusCode) {
			case 200:
				message = "OK";
				break;
			case 300:
				message = "ERR";
				break;
			case 400:
				message = "AUTHFAIL";
				break;
			case 500:
				message = "INTERR";
				break;
		}
	}
	
	if (req && req.version && req.requestId && returnPath && statusCode) {
		debug('Authentication response: %s', req ? JSON.stringify({
			version: req.version,
			requestId: req.requestId,
			statusCode: statusCode,
			message: message,
			userId: userId,
			metadata: metadata
		}, true, 2) : 'undefined');
	
		return (returnPath || []).splice(0).concat([
			new Buffer(req.version, 'utf8'),
			new Buffer(req.requestId, 'utf8'),
			new Buffer(statusCode.toString(), 'utf8'),
			(message ? new Buffer(message, 'utf8') : new Buffer(0)),
			(((statusCode == 200) && userId) ? new Buffer(userId, 'utf8') : new Buffer(0)),
			(((statusCode == 200) && (metadata)) ? metadata : new Buffer(0))
		]);
	} else {
		return;
	}
}

ZAP.prototype.use = function(mechanism) {
	if (!mechanism) throw new Error('Invalid mechanism');
	if ((typeof mechanism.name !== 'string') || !mechanism.name.length) throw new Error("Invalid mechanism name");
	if (typeof mechanism.authenticate !== 'function') throw new Error('Invalid mechanism authenticate handler');
	
	this._mechanisms[mechanism.name] = mechanism;
}

ZAP.prototype.authenticate = function(data, callback) {
	var data = Array.prototype.slice.call(data); // This forces data to be an array (for when 'arguments' is passed in directly)
	
	var returnPath = this._captureReturnPath(data),
		req = this._parseRequestData(data),
		mech = this._mechanisms[req.mechanism];
	
	if (req && this._validateRequest(req, mech)) {
		debug('Authentication request: %s', JSON.stringify(req, true, 2));
		
{'fraction_non_alphanumeric': 0.16606379480434066, 'fraction_numerical': 0.013153567905294311, 'mean_word_length': 4.364197530864198, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '1291145', 'n_tokens_mistral': 2187, 'n_tokens_neox': 1960, 'n_words': 489}