// Original file created by Prof.Dr. Matthias Hopf

/*
 * Valdiate ohm logins with ldap service
 */
const ldap = require('ldapjs');
const ldap_escape = require('ldap-escape');


// NOTE: Where do I get the URL from?? A: Is given.
var ldap_client = ldap.createClient({
  //url: 'ldap://gso2.ads1.fh-nuernberg.de/',
  url: 'ldap://sso.cs.ohm-hochschule.de:389/',
  //url: 'ldaps://sso.cs.ohm-hochschule.de:636/',
  reconnect: true,
  // timeouts don't work reliably
});

// NOTE: Where do I get the 'bindpath' parameters info from? A: Is given.
const ldap_config = {
    bindpath: 'cn=Users,dc=ohm-hochschule,dc=de',
    timeout: 2000
};

const ldap_ohm = {
    init: function () {
    },

    // Authorize user with password
    // Calls callback with null if unauthorized
    // Calls callback with object describing user if successful:
    authorize: function (user, pwd, cb) {
        if (typeof user != 'string' || typeof pwd != 'string')
            return cb (null);
        // Empty passwords *may* bind successfully anonymously
        if (user.length < 1 || pwd.length < 1)
            return cb (null);

        /* Same function, different writing style */
		/* Escape ldap login input */
        //escaped = ldap_escape.dn`cn=${user},`+ldap_config.bindpath;
        escaped = ldap_escape.dn (['cn=',','+ldap_config.bindpath], user);

        // Timeout handler: call callback,
        // make sure later ldap returns don't do anything weird
        var return_object = {};
        var timeoutHandle = setTimeout (function () {
            console.log('ldap timeout');
            return_object = null;
            cb (null);
        }, ldap_config.timeout);

        // Bind ldap to user (authorize)
        ldap_client.bind (escaped, pwd, function (err, res) {
            if (return_object === null)
                return;                 // Timeout, cb has already been called
            if (err !== null) {
                console.log ("ldap bind: failed for user " + user + ": " + err);
                clearTimeout (timeoutHandle);
                return cb (null);
            }

            // Search for user entry of just bound user
            // There should be only one...
            ldap_client.search (escaped, { sizeLimit: 1 }, function (err, res) {
                if (return_object === null)
                    return;             // Timeout, cb has already been called
                if (err !== null) {
                    console.log ("ldap search: search after bind didn't work for user "
                                 + user + ": " + err);
                    clearTimeout (timeoutHandle);
                    return cb (null);
                }
                // Populate return with search results
                res.on('searchEntry', function(entry) {
                    if (return_object === null)
                        return;         // Timeout, cb has already been called
                    return_object.user = user;
                    return_object.name = entry.object.displayname;
                    return_object.type = entry.object.employeetype;
                    return_object.mail = entry.object.mail;
                    return_object.gender = entry.object.orclgender;

                    // Calling cb here, not in 'end', because of potential bugs with
                    // concurrency failures, and we have our single(!) entry
                    // https://github.com/joyent/node-ldapjs/pull/424
                    clearTimeout (timeoutHandle);
                    if (typeof return_object.mail != 'string' || return_object.mail.length < 1) {
                        console.log("ldap search error after bind for user " + user);
                        return cb (null);
                    }
                    // ldap_test output
//                    return_object = entry.object;
                    return cb (return_object);
                });
                res.on('error', function(err) {
                    console.log('ldap error: ' + err.message);
                });
                res.on('end', function(result) {
                    // TODO: analyze result.status?
//                    console.info('ldap result: ');
//                    console.info(result);
                });
            });
        });
    }
};

module.exports = ldap_ohm;
