dataflo.ws
Version:
Zero-code JSON config-based dataflow engine for Node, PhoneGap and browser.
453 lines (386 loc) • 13.3 kB
JavaScript
var util = require('util'),
https = require('https'),
url = require('url'),
crypto = require ('crypto'),
crack = require("crack"),
spawn = require('child_process').spawn;
task = require('./base');
var exchangeConfig = project.config.consumerConfig.exchange;
var wsdlUrl = exchangeConfig.wsdlUrl;
var servicesUrl = exchangeConfig.servicesUrl;
var exchange = module.exports = function (config) {
this.init (config);
};
util.inherits(exchange, task);
util.extend(exchange.prototype, {
run: function () {
this.failed('use method [login|profile|check|searchUsers]');
},
login: function () {
var self = this,
login = self.credentials.login,
password = self.credentials.password;
//var auth = 'Basic ' + new Buffer(login + ":" + password).toString('base64');
var options = url.parse(wsdlUrl);
options.method = 'GET';
var processNtlmResponse = function(exit_code, err, data){
//console.log('data', data, exit_code);
switch (exit_code)
{
case 0:
console.log('login completed 200');
self.completed({
statusCode: 200,
err: '',
accessAllowed: true,
success: true
});
break;
default:
console.log('login completed 401');
self.completed({
statusCode: 401,
err: 'User not authorized',
accessAllowed: false,
success: false
});
break;
}
};
var processBasicResponse = function(response){
switch (response.statusCode)
{
case 200:
self.completed({
statusCode: 200,
err: '',
accessAllowed: true,
success: true
});
break;
default:
self.completed({
statusCode: 401,
err: 'User not authorized',
accessAllowed: false,
success: false
});
break;
}
response.destroy();
};
if (self.exchangeAuthType == 'ntlm') {
this.getNtlmRequest(
[
wsdlUrl,
'--ntlm',
'-f',
'-s',
'-S',
'--user',
login + ':' + password
],
processNtlmResponse
);
} else {
options.auth = login + ":" + password;
var req = this.getBasicRequest(options, processBasicResponse);
req.on('error', function(e) {
console.error(e);
});
req.end();
}
},
getBasicRequest: function (options, responseCb) {
var req = https.request(options, responseCb);
return req;
},
getNtlmRequest: function (options, callback) {
//console.log('options', options);
var curl = spawn('curl',
options
/*[
'https://pochta.rian.ru/EWS/Exchange.asmx',
'-H',
'Content-Type: text/xml',
'--ntlm',
'-f',
'-s',
'-S',
'--user',
login + ':' + password,
'-d',
'<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"><soap:Body><ResolveNames xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" ReturnFullContactData="true"><UnresolvedEntry>bakhcheev</UnresolvedEntry></ResolveNames></soap:Body></soap:Envelope>'
]*/
),
data = '',
err = null;
curl.stdout.on('data', function(chunk) {
data += chunk;
});
curl.stderr.on('data', function(err_msg) {
if (err === null) { err = ''; }
err += err_msg;
});
curl.on('error', function (err){console.error(err);});
curl.on('exit', function(exit_code) {
callback(exit_code, err, data);
});
},
encode: function (str) {
return new Buffer(str).toString('base64');
},
decode: function (str) {
return new Buffer(str, 'base64').toString('utf8');
},
profile: function() {
var self = this,
ldapRequest = self.ldapResponse,
sessionUID = self.sessionUID,
user = ldapRequest.data && ldapRequest.data.length && ldapRequest.data[0],
credentials = self.credentials;
if (user) {
if (Object.prototype.toString.call( user.memberof ) === '[object String]') {
// we came here from login
user.memberof = [ user.memberof ];
} else {
// we came here from ldap
user.memberof = user.memberof.map(function(item) {
return item.split(',')[0].split('=')[1];
});
}
var result = {
email: user.mail || user.email,
name: user.cn || user.name,
groupIds: user.memberof,
sessionUIDs: sessionUID,
authType: 'exchange',
tokens: {
login: credentials.login,
password: this.encode(credentials.password)
}
};
if (user.thumbnailphoto){
var shasum = crypto.createHash('sha1');
shasum.update(user.mail);
var filePath = '/images/avatars/'+shasum.digest('hex')+'.png';
var cacheFileStream = project.root.fileIO('htdocs'+filePath).writeStream({flags: 'w', mode: 0666});
cacheFileStream.write(new Buffer(user.thumbnailphoto, 'base64'));
result.avatar = filePath;
}
if (user.department){
result.department = user.department;
}
if (user.division){
result.division = user.division;
}
self.completed(result);
} else {
self.failed({
statusCode: 404,
msg: 'User Not Found!'
});
}
},
check: function() {
var self = this,
user = self.user;
if (user && user.authType == 'exchange' && user.tokens && user.tokens.login && user.tokens.password) {
self.credentials = {
login: user.tokens.login,
password: this.decode(user.tokens.password)
};
self.login();
} else {
self.completed({
accessAllowed: true
});
}
},
tmpl: function (str, obj) {
return str.replace(
/{\$(.+?)}/g,
function (_, key) { return obj[key]; }
);
},
prepareQuery: function () {
var queryTpl = [
'<?xml version="1.0" encoding="utf-8"?>',
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">',
'<soap:Body>',
'<ResolveNames xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" ReturnFullContactData="true">',
'<UnresolvedEntry>{$filter}</UnresolvedEntry>',
'</ResolveNames>',
'</soap:Body>',
'</soap:Envelope>'
].join(' ');
},
encodePassword: function () {
this.completed({
password: this.encode(this.plainPassword)
});
},
searchUsers: function () {
var self = this,
user = self.user;
if (user && user.authType == 'exchange' && user.tokens && user.tokens.login && user.tokens.password) {
var login = user.tokens.login,
password = this.decode(user.tokens.password);
var options = url.parse(servicesUrl);
var queryTpl = [
'<?xml version="1.0" encoding="utf-8"?>',
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">',
'<soap:Body>',
'<ResolveNames xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" ReturnFullContactData="true">',
'<UnresolvedEntry>{$filter}</UnresolvedEntry>',
'</ResolveNames>',
'</soap:Body>',
'</soap:Envelope>'
].join(' ');
var query = this.tmpl(queryTpl, this.pager);
options.auth = login + ':' + password;
options.port = 443;
options.headers = {
'Content-Type': 'text/xml'
};
options.method = 'POST';
var processNtlmResponse = function(exit_code, err, data){
//console.log('data', data, exit_code);
switch (exit_code)
{
case 0:
console.log('searchUsers completed 200');
// process data
processData(data);
break;
default:
console.log('searchUsers completed 401');
self.completed({
data: null,
total: 0,
success: false,
error: '401 - not authorized'
});
break;
}
};
var processData = function (exchangeXmlAnswer) {
var error = '';
var users = [];
var crackedResponse = crack(exchangeXmlAnswer);
var objResponse = crackedResponse.toJS();
if (objResponse.Body.Fault) {
console.log('!!!!!!!!!!!!!!! RESPONSE FAULT:', objResponse.Body.Fault.faultstring.__content);
self.failed({
statusCode: 500,
msg: 'Response Fault!'
});
return;
}
var objResolveNamesResponseMessage = objResponse.Body.ResolveNamesResponse.ResponseMessages.ResolveNamesResponseMessage;
if (objResolveNamesResponseMessage.ResponseClass != 'Success' && objResolveNamesResponseMessage.ResponseClass != 'Warning'){
console.log('!!!!!!!!!!!!!!! NOT SUCCESS!');
self.failed({
statusCode: 500,
msg: 'Response Not Success!'
});
error = 'Response Not Success!';
//return;
}
if (!error) {
var objResolutionSet = objResolveNamesResponseMessage.ResolutionSet;
if (Object.prototype.toString.call( objResolutionSet ) === '[object Array]') {
console.log('Found: ' + objResolutionSet.TotalItemsInView);
console.log('Query:', self.pager.filter);
}
if (Object.prototype.toString.call( objResolutionSet.Resolution ) === '[object Array]') {
objResolutionSet.Resolution.forEach(function (objResolution){
var objMailbox = objResolution.Mailbox;
var objContact = objResolution.Contact;
users.push({
name: objMailbox.Name,
authType: 'exchange',
avatar: '',
email: objMailbox.EmailAddress,
_id: objMailbox.EmailAddress,
text: objMailbox.Name,
memberof: objContact.Department
});
//console.log('Name: ' + objMailbox.Name);
//console.log('Email: ' + objMailbox.EmailAddress);
});
} else if (Object.prototype.toString.call( objResolutionSet.Resolution ) === '[object Object]') {
users.push({
name: objResolutionSet.Resolution.Mailbox.Name,
link: undefined,
authType: 'exchange',
avatar: '',
email: objResolutionSet.Resolution.Mailbox.EmailAddress,
_id: objResolutionSet.Resolution.Mailbox.EmailAddress,
text: objResolutionSet.Resolution.Mailbox.Name,
memberof: objResolutionSet.Resolution.Contact.Department
});
//console.log('Name: ' + objResolutionSet.Resolution.Mailbox.Name);
//console.log('Email: ' + objResolutionSet.Resolution.Mailbox.EmailAddress);
}
}
self.completed({
data: users || null,
total: users ? users.length : 0,
success: !error,
error: error
});
}
var processBasicResponse = function (response) {
var exchangeXmlAnswer = [];
response.setEncoding('utf-8');
response.on('data', function (data) {
exchangeXmlAnswer.push(data);
});
response.on('end', function () {
if (exchangeXmlAnswer.length) {
exchangeXmlAnswer = exchangeXmlAnswer.join('');
// process data
processData(exchangeXmlAnswer);
}
self.completed({
data: users || null,
total: users ? users.length : 0,
success: !error,
error: error
});
});
}
// RUN REQUEST!!!
if (self.exchangeAuthType=='ntlm') {
this.getNtlmRequest(
[
servicesUrl,
'-H',
'Content-Type: text/xml',
'--ntlm',
'-f',
'-s',
'-S',
'--user',
login + ':' + password,
'-d',
query
],
processNtlmResponse
);
} else {
options.auth = login + ":" + password;
var req = this.getBasicRequest(options, processBasicResponse);
req.on('error', function(e) {
console.error(e);
});
req.write(query);
req.end();
}
} else {
self.completed({
});
}
}
});