All files / node-activedirectory/lib/services service.findDeletedObjects.js

14.58% Statements 7/48
0% Branches 0/30
0% Functions 0/6
14.89% Lines 7/47

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 1071x 1x 1x 1x 1x 1x                                                                                                                                                                                                         1x
const _                                 = require('underscore');
const joinAttributes                    = require('./internal/service.joinAttributes');
const search                            = require('./internal/service.search');
const truncateLogOutput                 = require('./internal/service.truncateLogOutput');
const pickAttributes                    = require('./internal/service.pickAttributes');
const log                               = require('./internal/service.log');
 
/**
 * Perform a generic search on the Deleted Objects container for active directory. For this function
 * to work correctly, the tombstone feature for active directory must be enabled. A tombstoned object
 * has most of the attributes stripped from the object.
 *
 * @public
 * @param {Object} [opts] Optional LDAP query string parameters to execute. { scope: '', filter: '', attributes: [ '', '', ... ], sizeLimit: 0, timelimit: 0 }. Optionally, if only a string is provided, then the string is assumed to be an LDAP filter.
 * @param {Function} callback The callback to execute when completed. callback(err: {Object}, result: [ ])
 */
function findDeletedObjects(opts, callback) {
    var self = this;
    return new Promise((resolve, reject) => {
        if (typeof (opts) === 'function') {
            callback = opts;
            opts = undefined;
        }
        if (typeof (opts) === 'string') {
            opts = {
                filter: opts
            };
        }
        log.trace('findDeletedObjects(%j)', opts);
    
        var defaultDeletedAttributes = [
            'attributeID', 'attributeSyntax', 'dnReferenceUpdate', 'dNSHostName', 'flatName',
            'governsID', 'groupType', 'instanceType', 'lDAPDisplayName', 'legacyExchangeDN',
            'mS-DS-CreatorSID', 'mSMQOwnerID', 'nCName', 'objectClass', 'objectGUID', 'objectSid',
            'oMSyntax', 'proxiedObjectName', 'replPropertyMetaData', 'sAMAccountName', 'securityIdentifier',
            'sIDHistory', 'subClassOf', 'systemFlags', 'trustPartner', 'trustDirection', 'trustType',
            'trustAttributes', 'userAccountControl', 'uSNChanged', 'uSNCreated', 'whenCreated',
            'msDS-AdditionalSam­AccountName', 'msDS-Auxiliary-Classes', 'msDS-Entry-Time-To-Die',
            'msDS-IntId', 'msSFU30NisDomain', 'nTSecurityDescriptor', 'uid'
        ];
    
        /**
         * Performs the actul search of the specified baseDN for any deleted (tombstoned) objects.
         * @param {String} baseDN The baseDN to search on.
         * @param {Object} opts The ldapjs query options.
         */
        function searchDeletedObjects(baseDN, opts) {
            search.call(self, baseDN, _.defaults({}, opts, { includeDeleted: true }), function onFind(err, results) {
                if (err) {
                    if (callback){
                        callback(err);
                    }
                    return reject(err);
                }
    
                if ((!results) || (results.length === 0)) {
                    log.warn('No deleted objects found for query "%s"', truncateLogOutput(opts.filter));
                    if (callback){
                        callback();
                    }
                    self.emit('done');
                    return resolve([]);
                }
    
                var deletedItems = [];
    
                // Parse the results in parallel.
                _.forEach(deletedItemss, function (item) {
                    var deletedItem = pickAttributes(item, (opts | {}).attributes || []);
                    self.emit('entry:deleted', deletedItem);
                    deletedItems.push(deletedItem);
                });
    
                log.info('%d deleted objects found for query "%s". Results: %j',
                    deletedItems.length, truncateLogOutput(localOpts.filter), deletedItems);
                self.emit('deleted', deletedItems);
                if (callback){
                    callback(null, deletedItems);
                }
                return resolve(deletedItems);
            });
        }
    
        var localOpts = _.defaults(opts || {}, {
            scope: 'one',
            attributes: joinAttributes((opts || {}).attributes || [], defaultDeletedAttributes),
            controls: []
        });
        // Get the BaseDN for the tree
        if (!localOpts.baseDN) {
            log.debug('No baseDN specified for Deleted Object. Querying RootDSE at %s.', self.opts.url);
            ActiveDirectory.prototype.getRootDSE(self.opts.url, ['defaultNamingContext'], function (err, result) {
                if (err) {
                    if (callback) callback(err);
                    return;
                }
    
                log.info('Retrieved defaultNamingContext (%s) from RootDSE at %s.', result.defaultNamingContext, self.opts.url);
                searchDeletedObjects('CN=Deleted Objects,' + result.defaultNamingContext, localOpts);
            });
        }
        else searchDeletedObjects(localOpts.baseDN, localOpts);
    });
    
};
 
module.exports = findDeletedObjects;