diff --git a/js/x11/core/auth.js b/js/x11/core/auth.js new file mode 100644 index 0000000..1bbec00 --- /dev/null +++ b/js/x11/core/auth.js @@ -0,0 +1,110 @@ +// TODO: differentiate between auth types (i.e., MIT-MAGIC-COOKIE-1 and XDM-AUTHORIZATION-1) +// and choose the best based on the algorithm in libXau's XauGetBestAuthByAddr + +var fs = Require('fs'); +var Buffer = Require('buffer').Buffer; +// add 'unpack' method for buffer +Require('x11/core/unpackbuffer').addUnpack(Buffer); + +var typeToName = { + 256: 'Local', + 65535: 'Wild', + 254: 'Netname', + 253: 'Krb5Principal', + 252: 'LocalHost', + 0: 'Internet', + 1: 'DECnet', + 2: 'Chaos', + 5: 'ServerInterpreted', + 6: 'Internet6' +}; + +function parseXauth( buf ) +{ + var offset = 0; + var auth = []; + var cookieProperties = ['address', 'display', 'authName', 'authData']; + + while (offset < buf.length) + { + var cookie = {}; + cookie.type = buf.readUInt16BE(offset); + if (!typeToName[cookie.type]) { + console.warn('Unknown address type'); + } + offset += 2; + cookieProperties.forEach(function(property) { + var length = buf.unpack('n', offset)[0]; + offset += 2; + if (cookie.type === 0 && property == 'address') { // Internet + // 4 bytes of ip addess, convert to w.x.y.z string + cookie.address = [ buf[offset], buf[offset+1], buf[offset+2], buf[offset+3]] + .map(function(octet) { return octet.toString(10) }).join('.'); + } else { + cookie[property] = buf.unpackString(length, offset); + } + offset += length; + }); + auth.push(cookie); + } + return auth; +} + +var homedir = Require('os/os-homedir'); +var path = Require('path'); + +function readXauthority(cb) { + var filename = process.env.XAUTHORITY || path.join(homedir(), '.Xauthority'); + fs.readFile(filename, function(err, data) { + if (!err) + return cb(null, data); + if(err.code == 'ENOENT') { + // Xming/windows uses %HOME%/Xauthority ( .Xauthority with no dot ) - try with this name + filename = process.env.XAUTHORITY || path.join(homedir(), 'Xauthority'); + fs.readFile(filename, function (err, data) { + if (err.code == 'ENOENT') { + cb(null, null); + } else { + cb(err); + } + }); + } else { + cb(err); + } + }); +} + +module.exports = function( display, host, socketFamily, cb ) +{ + var family; + if (socketFamily === 'IPv4') { + family = 0; // Internet + } else if (socketFamily === 'IPv6') { + family = 6; // Internet6 + } else { + family = 256; // Local + } + readXauthority(function(err, data) { + if(err) return cb(err); + + if (!data) { + return cb(null, { + authName: '', + authData: '' + }); + } + var auth = parseXauth(data); + for (var cookieNum in auth) + { + var cookie = auth[cookieNum]; + if ((typeToName[cookie.family] === 'Wild' || (cookie.type === family && cookie.address === host)) && + (cookie.display.length === 0 || cookie.display === display)) + return cb( null, cookie ); + } + // If no cookie is found, proceed without authentication + cb(null, { + authName: '', + authData: '' + }); + }); +};