123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- 'use strict';
- var path = require('path')
- , Stream = require('stream').Stream
- , split = require('split2')
- , util = require('util')
- , defaultPort = 5432
- , isWin = (process.platform === 'win32')
- , warnStream = process.stderr
- ;
- var S_IRWXG = 56 // 00070(8)
- , S_IRWXO = 7 // 00007(8)
- , S_IFMT = 61440 // 00170000(8)
- , S_IFREG = 32768 // 0100000(8)
- ;
- function isRegFile(mode) {
- return ((mode & S_IFMT) == S_IFREG);
- }
- var fieldNames = [ 'host', 'port', 'database', 'user', 'password' ];
- var nrOfFields = fieldNames.length;
- var passKey = fieldNames[ nrOfFields -1 ];
- function warn() {
- var isWritable = (
- warnStream instanceof Stream &&
- true === warnStream.writable
- );
- if (isWritable) {
- var args = Array.prototype.slice.call(arguments).concat("\n");
- warnStream.write( util.format.apply(util, args) );
- }
- }
- Object.defineProperty(module.exports, 'isWin', {
- get : function() {
- return isWin;
- } ,
- set : function(val) {
- isWin = val;
- }
- });
- module.exports.warnTo = function(stream) {
- var old = warnStream;
- warnStream = stream;
- return old;
- };
- module.exports.getFileName = function(rawEnv){
- var env = rawEnv || process.env;
- var file = env.PGPASSFILE || (
- isWin ?
- path.join( env.APPDATA || './' , 'postgresql', 'pgpass.conf' ) :
- path.join( env.HOME || './', '.pgpass' )
- );
- return file;
- };
- module.exports.usePgPass = function(stats, fname) {
- if (Object.prototype.hasOwnProperty.call(process.env, 'PGPASSWORD')) {
- return false;
- }
- if (isWin) {
- return true;
- }
- fname = fname || '<unkn>';
- if (! isRegFile(stats.mode)) {
- warn('WARNING: password file "%s" is not a plain file', fname);
- return false;
- }
- if (stats.mode & (S_IRWXG | S_IRWXO)) {
- /* If password file is insecure, alert the user and ignore it. */
- warn('WARNING: password file "%s" has group or world access; permissions should be u=rw (0600) or less', fname);
- return false;
- }
- return true;
- };
- var matcher = module.exports.match = function(connInfo, entry) {
- return fieldNames.slice(0, -1).reduce(function(prev, field, idx){
- if (idx == 1) {
- // the port
- if ( Number( connInfo[field] || defaultPort ) === Number( entry[field] ) ) {
- return prev && true;
- }
- }
- return prev && (
- entry[field] === '*' ||
- entry[field] === connInfo[field]
- );
- }, true);
- };
- module.exports.getPassword = function(connInfo, stream, cb) {
- var pass;
- var lineStream = stream.pipe(split());
- function onLine(line) {
- var entry = parseLine(line);
- if (entry && isValidEntry(entry) && matcher(connInfo, entry)) {
- pass = entry[passKey];
- lineStream.end(); // -> calls onEnd(), but pass is set now
- }
- }
- var onEnd = function() {
- stream.destroy();
- cb(pass);
- };
- var onErr = function(err) {
- stream.destroy();
- warn('WARNING: error on reading file: %s', err);
- cb(undefined);
- };
- stream.on('error', onErr);
- lineStream
- .on('data', onLine)
- .on('end', onEnd)
- .on('error', onErr)
- ;
- };
- var parseLine = module.exports.parseLine = function(line) {
- if (line.length < 11 || line.match(/^\s+#/)) {
- return null;
- }
- var curChar = '';
- var prevChar = '';
- var fieldIdx = 0;
- var startIdx = 0;
- var endIdx = 0;
- var obj = {};
- var isLastField = false;
- var addToObj = function(idx, i0, i1) {
- var field = line.substring(i0, i1);
- if (! Object.hasOwnProperty.call(process.env, 'PGPASS_NO_DEESCAPE')) {
- field = field.replace(/\\([:\\])/g, '$1');
- }
- obj[ fieldNames[idx] ] = field;
- };
- for (var i = 0 ; i < line.length-1 ; i += 1) {
- curChar = line.charAt(i+1);
- prevChar = line.charAt(i);
- isLastField = (fieldIdx == nrOfFields-1);
- if (isLastField) {
- addToObj(fieldIdx, startIdx);
- break;
- }
- if (i >= 0 && curChar == ':' && prevChar !== '\\') {
- addToObj(fieldIdx, startIdx, i+1);
- startIdx = i+2;
- fieldIdx += 1;
- }
- }
- obj = ( Object.keys(obj).length === nrOfFields ) ? obj : null;
- return obj;
- };
- var isValidEntry = module.exports.isValidEntry = function(entry){
- var rules = {
- // host
- 0 : function(x){
- return x.length > 0;
- } ,
- // port
- 1 : function(x){
- if (x === '*') {
- return true;
- }
- x = Number(x);
- return (
- isFinite(x) &&
- x > 0 &&
- x < 9007199254740992 &&
- Math.floor(x) === x
- );
- } ,
- // database
- 2 : function(x){
- return x.length > 0;
- } ,
- // username
- 3 : function(x){
- return x.length > 0;
- } ,
- // password
- 4 : function(x){
- return x.length > 0;
- }
- };
- for (var idx = 0 ; idx < fieldNames.length ; idx += 1) {
- var rule = rules[idx];
- var value = entry[ fieldNames[idx] ] || '';
- var res = rule(value);
- if (!res) {
- return false;
- }
- }
- return true;
- };
|