Merge pull request #620 from ldapjs/next

Release v2!
This commit is contained in:
James Sumners 2020-05-31 09:10:01 -04:00 committed by GitHub
commit e54555ae0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
166 changed files with 9676 additions and 10624 deletions

View File

@ -1,6 +0,0 @@
((nil . ((indent-tabs-mode . nil)
(tab-width . 8)
(fill-column . 80)))
(js-mode . ((js-indent-level . 2)
(indent-tabs-mode . nil)
)))

41
.github/workflows/integration.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: 'Integration Tests'
# Notes:
# https://github.community/t5/GitHub-Actions/Github-Actions-services-not-reachable/m-p/30739/highlight/true#M538
on:
pull_request:
branches:
- master
- next
jobs:
baseline:
name: Baseline Tests
runs-on: ubuntu-latest
# services:
# openldap:
# image: docker.pkg.github.com/ldapjs/docker-test-openldap/openldap:1.0
# ports:
# - 389:389
# - 636:636
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
# Hack way to start service since GitHub doesn't integrate with its own services
- name: Docker login
run: docker login docker.pkg.github.com -u ${GITHUB_ACTOR} -p ${GITHUB_TOKEN}
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Pull Docker image
run: docker pull "docker.pkg.github.com/ldapjs/docker-test-openldap/openldap:latest"
- name: Start OpenLDAP service
run: docker run -it -d --name openldap -p 389:389 -p 636:636 docker.pkg.github.com/ldapjs/docker-test-openldap/openldap:latest
- name: Install Packages
run: npm install
- name: Run Tests
run: npm run test:integration

51
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,51 @@
name: 'Lint And Test'
on:
pull_request:
branches:
- master
- next
jobs:
lint:
name: Lint Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- name: Install Packages
run: npm install
- name: Lint Code
run: npm run lint:ci
run_tests:
name: Unit Tests
strategy:
matrix:
os:
- ubuntu-latest
- windows-latest
node:
- 10.13.0
- 10.x
- 12.x
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
- name: Install Packages
run: npm install
- name: Run Tests
run: npm run test:ci
- name: Coveralls Parallel
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel: true
- name: Coveralls Finished
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel-finished: true

77
.gitignore vendored
View File

@ -1,8 +1,77 @@
build
node_modules
coverage
*.log
*.ldif
*.tar.*
*.tgz
# Lock files
pnpm-lock.yaml
shrinkwrap.yaml
package-lock.json
yarn.lock
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
node_modules
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
# 0x
.__browserify_string_empty.js
profile-*
*.flamegraph
# tap --cov
.nyc_output/
# JetBrains IntelliJ IDEA
.idea/
*.iml
# VS Code
.vscode/
# xcode
build/*
*.mode1
*.mode1v3
*.mode2v3
*.perspective
*.perspectivev3
*.pbxuser
*.xcworkspace
xcuserdata
# macOS
.DS_Store
# keys
*.pem
*.env.json
*.env

9
.gitmodules vendored
View File

@ -1,9 +0,0 @@
[submodule "deps/javascriptlint"]
path = deps/javascriptlint
url = https://github.com/davepacheco/javascriptlint
[submodule "deps/jsstyle"]
path = deps/jsstyle
url = https://github.com/davepacheco/jsstyle
[submodule "deps/restdown"]
path = deps/restdown
url = https://github.com/trentm/restdown

6
.taprc Normal file
View File

@ -0,0 +1,6 @@
esm: false
jsx: false
ts: false
files:
- 'test/**/*.test.js'

View File

@ -1,6 +0,0 @@
language: node_js
node_js:
- "0.10"
- "0.12"
- "4"
- "stable"

View File

@ -1,5 +1,9 @@
# ldapjs Changelog
## 2.0.0
- Going foward, please see https://github.com/ldapjs/node-ldapjs/releases
## 1.0.2
- Update dtrace-provider dependency

View File

@ -1,4 +1,4 @@
Copyright (c) 2011 Mark Cavage, All rights reserved.
Copyright (c) 2019 LDAPjs, All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,58 +0,0 @@
#
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
#
# Makefile: basic Makefile for template API service
#
# This Makefile is a template for new repos. It contains only repo-specific
# logic and uses included makefiles to supply common targets (javascriptlint,
# jsstyle, restdown, etc.), which are used by other repos as well. You may well
# need to rewrite most of this file, but you shouldn't need to touch the
# included makefiles.
#
# If you find yourself adding support for new targets that could be useful for
# other projects too, you should add these to the original versions of the
# included Makefiles (in eng.git) so that other teams can use them too.
#
#
# Tools
#
NPM := npm
TAP := ./node_modules/.bin/tap
#
# Files
#
DOC_FILES := $(shell find docs -name '*.md' -printf '%f\n')
RESTDOWN_FLAGS := -b docs/branding/
JS_FILES := $(shell find lib test -name '*.js') $(shell find bin -name 'ldapjs-*')
JSL_CONF_NODE = tools/jsl.node.conf
JSL_FILES_NODE = $(JS_FILES)
JSSTYLE_FILES = $(JS_FILES)
JSSTYLE_FLAGS = -f tools/jsstyle.conf
CLEAN_FILES += node_modules coverage $(SHRINKWRAP) cscope.files
include ./tools/mk/Makefile.defs
# Repo-specific targets
#
.PHONY: all
all: $(TAP) $(REPO_DEPS)
$(NPM) rebuild
$(TAP): | $(NPM_EXEC)
$(NPM) install
CLEAN_FILES += $(TAP) ./node_modules/tap
.PHONY: test
test: $(TAP)
$(NPM) test
.PHONY: cover
cover: test
$(NPM) run report
include ./tools/mk/Makefile.deps
include ./tools/mk/Makefile.targ

View File

@ -1,9 +1,7 @@
# LDAPjs
[!['Build status'][travis_image_url]][travis_page_url]
[travis_image_url]: https://api.travis-ci.org/joyent/node-ldapjs.svg
[travis_page_url]: https://travis-ci.org/joyent/node-ldapjs
[![Build Status](https://github.com/ldapjs/node-ldapjs/workflows/.github/workflows/main.yml/badge.svg)]
[![Coverage Status](https://coveralls.io/repos/github/ldapjs/node-ldapjs/badge.svg)]
LDAPjs makes the LDAP protocol a first class citizen in Node.js.
@ -45,10 +43,12 @@ client on your system:
npm install ldapjs
DTrace support is included in ldapjs. To enable it, `npm install dtrace-provider`.
## License
MIT.
## Bugs
See <https://github.com/mcavage/node-ldapjs/issues>.
See <https://github.com/ldapjs/node-ldapjs/issues>.

View File

@ -1,171 +0,0 @@
#!/usr/bin/env node
// -*- mode: js -*-
// Copyright 2011 Mark Cavage. All rights reserved.
var fs = require('fs');
var path = require('path');
var dashdash = require('dashdash');
var vasync = require('vasync');
var ldap = require('../lib/index');
var Logger = require('bunyan');
///--- Globals
var opts = [
{
names: ['file', 'f'],
type: 'string',
help: 'Input file',
helpArg: 'FILE'
},
{ group: 'General Options' },
{
names: ['help', 'h'],
type: 'bool',
help: 'Print this help and exit.'
},
{
names: ['debug', 'd'],
type: 'integer',
help: 'Set debug level <0-2>',
helpArg: 'LEVEL'
},
{ group: 'Connection Options' },
{
names: ['url', 'u'],
type: 'string',
help: 'LDAP server URL',
helpArg: 'URL',
default: 'ldap://127.0.0.1:389'
},
{
names: ['binddn', 'D'],
type: 'string',
help: 'Bind DN',
helpArg: 'BIND_DN',
default: ''
},
{
names: ['password', 'w'],
type: 'string',
help: 'Bind password',
helpArg: 'PASSWD',
default: ''
},
{
names: ['insecure', 'i'],
type: 'bool',
env: 'LDAPJS_TLS_INSECURE',
help: 'Disable SSL certificate verification',
default: false
}
];
var parser = dashdash.createParser({options: opts});
///--- Helpers
function usage(code, message) {
var msg = (message ? message + '\n' : '') +
'Usage: ' + path.basename(process.argv[1]) + ' [OPTIONS] [JSON]\n\n' +
parser.help({includeEnv: true});
process.stderr.write(msg + '\n');
process.exit(code);
}
function perror(err) {
if (parsed.debug) {
process.stderr.write(err.stack + '\n');
} else {
process.stderr.write(err.message + '\n');
}
process.exit(1);
}
///--- Mainline
var logLevel = 'info';
var parsed;
try {
parsed = parser.parse(process.argv);
if (parsed.file) {
parsed.file = JSON.parse(fs.readFileSync(parsed.file, 'utf8'));
if (!Array.isArray(parsed.file))
parsed.file = [parsed.file];
}
} catch (e) {
usage(1, e.toString());
}
if (parsed.help)
usage(0);
if (!parsed.file) {
parsed.file = [];
parsed._args.forEach(function (a) {
var o = JSON.parse(a);
if (Array.isArray(o)) {
o.forEach(function (i) {
parsed.file.push(o);
});
return;
}
parsed.file.push(o);
});
if (parsed.file.length === 0)
parsed.file = null;
}
if (!parsed.file)
usage(1, 'either -f or arguments must be used for adding objects');
if (parsed.debug)
logLevel = (parsed.debug > 1 ? 'trace' : 'debug');
var log = new Logger({
name: 'ldapjs',
component: 'client',
stream: process.stderr,
level: logLevel
});
var client = ldap.createClient({
url: parsed.url,
log: log,
strictDN: false,
tlsOptions: {
rejectUnauthorized: !parsed.insecure
}
});
client.on('error', function (err) {
perror(err);
});
client.bind(parsed.binddn, parsed.password, function (err, res) {
if (err) {
perror(err);
}
vasync.forEachPipeline({
inputs: parsed.file,
func: function (entry, cb) {
var dn = entry.dn;
delete entry.dn;
client.add(dn, entry, cb);
}
}, function (err2, res2) {
if (err2) {
perror(err2);
}
client.unbind(function () { return; });
});
});

View File

@ -1,167 +0,0 @@
#!/usr/bin/env node
// -*- mode: js -*-
// Copyright 2011 Mark Cavage. All rights reserved.
var fs = require('fs');
var path = require('path');
var dashdash = require('dashdash');
var ldap = require('../lib/index');
var Logger = require('bunyan');
///--- Globals
var opts = [
{
names: ['attribute', 'a'],
type: 'string',
help: 'Comparison attribute',
helpArg: 'ATTR'
},
{
names: ['value', 'v'],
type: 'string',
help: 'Comparison value',
helpArg: 'VAL'
},
{ group: 'General Options' },
{
names: ['help', 'h'],
type: 'bool',
help: 'Print this help and exit.'
},
{
names: ['debug', 'd'],
type: 'integer',
help: 'Set debug level <0-2>',
helpArg: 'LEVEL'
},
{ group: 'Connection Options' },
{
names: ['url', 'u'],
type: 'string',
help: 'LDAP server URL',
helpArg: 'URL',
default: 'ldap://127.0.0.1:389'
},
{
names: ['binddn', 'D'],
type: 'string',
help: 'Bind DN',
helpArg: 'BIND_DN',
default: ''
},
{
names: ['password', 'w'],
type: 'string',
help: 'Bind password',
helpArg: 'PASSWD',
default: ''
},
{
names: ['insecure', 'i'],
type: 'bool',
env: 'LDAPJS_TLS_INSECURE',
help: 'Disable SSL certificate verification',
default: false
}
];
var parser = dashdash.createParser({options: opts});
///--- Helpers
function usage(code, message) {
var msg = (message ? message + '\n' : '') +
'Usage: ' + path.basename(process.argv[1]) + ' [OPTIONS] DN\n\n' +
parser.help({includeEnv: true});
process.stderr.write(msg + '\n');
process.exit(code);
}
function perror(err) {
if (parsed.debug) {
process.stderr.write(err.stack + '\n');
} else {
process.stderr.write(err.message + '\n');
}
process.exit(1);
}
///--- Mainline
var logLevel = 'info';
var parsed;
try {
parsed = parser.parse(process.argv);
} catch (e) {
usage(1, e.toString());
}
if (parsed.help)
usage(0);
if (parsed._args.length < 1)
usage(1, 'DN required');
try {
parsed._args.forEach(function (dn) {
ldap.parseDN(dn);
});
} catch (e) {
usage(1, e.toString());
}
if (!parsed.attribute || typeof (parsed.value) !== 'string')
usage(1, 'attribute and value required');
if (parsed.debug)
logLevel = (parsed.debug > 1 ? 'trace' : 'debug');
var log = new Logger({
name: 'ldapjs',
component: 'client',
stream: process.stderr,
level: logLevel
});
var client = ldap.createClient({
url: parsed.url,
log: log,
strictDN: false,
tlsOptions: {
rejectUnauthorized: !parsed.insecure
}
});
client.on('error', function (err) {
perror(err);
});
client.bind(parsed.binddn, parsed.password, function (err, res) {
if (err)
perror(err);
var finished = 0;
parsed._args.forEach(function (dn) {
client.compare(dn, parsed.attribute, parsed.value, function (err, match) {
if (err)
perror(err);
process.stdout.write(match + '\n');
if (++finished === parsed._args.length) {
client.unbind(function () {
return;
});
}
});
});
});

View File

@ -1,148 +0,0 @@
#!/usr/bin/env node
// -*- mode: js -*-
// Copyright 2011 Mark Cavage. All rights reserved.
var fs = require('fs');
var path = require('path');
var dashdash = require('dashdash');
var ldap = require('../lib/index');
var Logger = require('bunyan');
///--- Globals
var opts = [
{ group: 'General Options' },
{
names: ['help', 'h'],
type: 'bool',
help: 'Print this help and exit.'
},
{
names: ['debug', 'd'],
type: 'integer',
help: 'Set debug level <0-2>',
helpArg: 'LEVEL'
},
{ group: 'Connection Options' },
{
names: ['url', 'u'],
type: 'string',
help: 'LDAP server URL',
helpArg: 'URL',
default: 'ldap://127.0.0.1:389'
},
{
names: ['binddn', 'D'],
type: 'string',
help: 'Bind DN',
helpArg: 'bind_DN',
default: ''
},
{
names: ['password', 'w'],
type: 'string',
help: 'Bind password',
helpArg: 'PASSWD',
default: ''
},
{
names: ['insecure', 'i'],
type: 'bool',
env: 'LDAPJS_TLS_INSECURE',
help: 'Disable SSL certificate verification',
default: false
}
];
var parser = dashdash.createParser({options: opts});
///--- Helpers
function usage(code, message) {
var msg = (message ? message + '\n' : '') +
'Usage: ' + path.basename(process.argv[1]) + ' [OPTIONS] DN\n\n' +
parser.help({includeEnv: true});
process.stderr.write(msg + '\n');
process.exit(code);
}
function perror(err) {
if (parsed.debug) {
process.stderr.write(err.stack + '\n');
} else {
process.stderr.write(err.message + '\n');
}
process.exit(1);
}
///--- Mainline
var logLevel = 'info';
var parsed;
try {
parsed = parser.parse(process.argv);
} catch (e) {
usage(1, e.toString());
}
if (parsed.help)
usage(0);
if (parsed._args.length < 1)
usage(1, 'DN required');
try {
parsed._args.forEach(function (dn) {
ldap.parseDN(dn);
});
} catch (e) {
usage(1, e.toString());
}
if (parsed.debug)
logLevel = (parsed.debug > 1 ? 'trace' : 'debug');
var log = new Logger({
name: 'ldapjs',
component: 'client',
stream: process.stderr,
level: logLevel
});
var client = ldap.createClient({
url: parsed.url,
log: log,
strictDN: false,
tlsOptions: {
rejectUnauthorized: !parsed.insecure
}
});
client.on('error', function (err) {
perror(err);
});
client.bind(parsed.binddn, parsed.password, function (err, res) {
if (err)
perror(err);
var finished = 0;
function callback(err) {
if (err)
perror(err);
if (++finished === parsed._args.length)
client.unbind(function () { return; });
}
parsed._args.forEach(function (dn) {
client.del(dn, callback);
});
});

View File

@ -1,185 +0,0 @@
#!/usr/bin/env node
// -*- mode: js -*-
// Copyright 2011 Mark Cavage. All rights reserved.
var fs = require('fs');
var path = require('path');
var dashdash = require('dashdash');
var ldap = require('../lib/index');
var Logger = require('bunyan');
///--- Globals
var opts = [
{
names: ['attribute', 'a'],
type: 'string',
help: 'Attribute to modify',
helpArg: 'ATTR'
},
{
names: ['value', 'v'],
type: 'arrayOfString',
help: 'Desired value',
helpArg: 'VAL'
},
{
names: ['type', 't'],
type: 'string',
help: 'Attribute type',
helpArg: 'TYPE'
},
{ group: 'General options' },
{
names: ['help', 'h'],
type: 'bool',
help: 'Print this help and exit.'
},
{
names: ['debug', 'd'],
type: 'integer',
help: 'Set debug level <0-2>',
helpArg: 'LEVEL'
},
{ group: 'Connection Options' },
{
names: ['url', 'u'],
type: 'string',
help: 'LDAP server URL',
helpArg: 'URL',
default: 'ldap://127.0.0.1:389'
},
{
names: ['binddn', 'D'],
type: 'string',
help: 'Bind DN',
helpArg: 'BIND_DN',
default: ''
},
{
names: ['password', 'w'],
type: 'string',
help: 'Bind password',
helpArg: 'PASSWD',
default: ''
},
{
names: ['insecure', 'i'],
type: 'bool',
env: 'LDAPJS_TLS_INSECURE',
help: 'Disable SSL certificate verification',
default: false
}
];
var parser = dashdash.createParser({options: opts});
///--- Helpers
function usage(code, message) {
var msg = (message ? message + '\n' : '') +
'Usage: ' + path.basename(process.argv[1]) + ' [OPTIONS] DN\n\n' +
parser.help({includeEnv: true});
process.stderr.write(msg + '\n');
process.exit(code);
}
function perror(err) {
if (parsed.debug) {
process.stderr.write(err.stack + '\n');
} else {
process.stderr.write(err.message + '\n');
}
process.exit(1);
}
///--- Mainline
var logLevel = 'info';
var parsed;
try {
parsed = parser.parse(process.argv);
} catch (e) {
usage(1, e.toString());
}
if (parsed.help)
usage(0);
if (parsed._args.length < 1)
usage(1, 'DN required');
try {
parsed._args.forEach(function (dn) {
ldap.parseDN(dn);
});
} catch (e) {
usage(1, e.toString());
}
if (!parsed.type)
parsed.type = 'replace';
if (!parsed.attribute || !Array.isArray(parsed.value))
usage(1, 'attribute and value required');
if (parsed.debug)
logLevel = (parsed.debug > 1 ? 'trace' : 'debug');
var log = new Logger({
name: 'ldapjs',
component: 'client',
stream: process.stderr,
level: logLevel
});
var client = ldap.createClient({
url: parsed.url,
log: log,
strictDN: false,
tlsOptions: {
rejectUnauthorized: !parsed.insecure
}
});
client.on('error', function (err) {
perror(err);
});
client.bind(parsed.binddn, parsed.password, function (err, res) {
if (err)
perror(err);
var finished = 0;
var mod = {};
mod[parsed.attribute] = [];
parsed.value.forEach(function (v) {
mod[parsed.attribute].push(v);
});
var change = new ldap.Change({
type: parsed.type,
modification: mod
});
function callback(err) {
if (err)
perror(err);
if (++finished === parsed._args.length) {
client.unbind(function () {
return;
});
}
}
parsed._args.forEach(function (dn) {
client.modify(dn, change, callback);
});
});

View File

@ -1,326 +0,0 @@
#!/usr/bin/env node
// -*- mode: js -*-
// Copyright 2011 Mark Cavage. All rights reserved.
var path = require('path');
var dashdash = require('dashdash');
var ldap = require('../lib/index');
var Logger = require('bunyan');
///--- Globals
dashdash.addOptionType({
name: 'ldap.Filter',
takesArg: true,
helpArg: 'LDAP_FILTER',
parseArg: function (option, optstr, arg) {
return ldap.parseFilter(arg);
}
});
dashdash.addOptionType({
name: 'ldap.scope',
takesArg: true,
helpArg: 'SCOPE',
parseArg: function (option, optstr, arg) {
if (!/^base|one|sub$/.test(arg)) {
throw new TypeError('Scope must be <base|one|sub>');
}
return arg;
}
});
dashdash.addOptionType({
name: 'ldap.outputFormat',
takesArg: true,
helpArg: 'FORMAT',
parseArg: function (option, optstr, arg) {
var formats = ['json', 'jsonl', 'jsona'];
if (formats.indexOf(arg) === -1) {
throw new TypeError('Must be valid format type');
}
return arg;
}
});
var opts = [
{
names: ['base', 'b'],
type: 'string',
help: 'Base DN of search',
helpArg: 'BASE_DN',
default: ''
},
{
names: ['scope', 's'],
type: 'ldap.scope',
help: 'Search scope <base|sub|one>',
helpArg: 'SCOPE',
default: 'sub'
},
{
names: ['timeout', 't'],
type: 'integer',
help: 'Search timeout',
helpArg: 'SECS'
},
{
names: ['persistent', 'p'],
type: 'bool',
help: 'Enable persistent search control',
default: false
},
{
names: ['paged', 'g'],
type: 'number',
help: 'Enable paged search result control',
helpArg: 'PAGE_SIZE'
},
{
names: ['control', 'c'],
type: 'arrayOfString',
help: 'Send addition control OID',
helpArg: 'OID',
default: []
},
{ group: 'General Options' },
{
names: ['help', 'h'],
type: 'bool',
help: 'Print this help and exit.'
},
{
names: ['debug', 'd'],
type: 'integer',
help: 'Set debug level <0-2>',
helpArg: 'LEVEL'
},
{ group: 'Output Options' },
{
names: ['format', 'o'],
type: 'ldap.outputFormat',
helpWrap: false,
help: ('Specify and output format. One of:\n' +
' json: JSON objects (default)\n' +
' jsonl: Line-delimited JSON\n' +
' jsona: Array of JSON objects\n'),
default: 'json'
},
{ group: 'Connection Options' },
{
names: ['url', 'u'],
type: 'string',
help: 'LDAP server URL',
helpArg: 'URL',
default: 'ldap://127.0.0.1:389'
},
{
names: ['binddn', 'D'],
type: 'string',
help: 'Bind DN',
helpArg: 'BIND_DN',
default: ''
},
{
names: ['password', 'w'],
type: 'string',
help: 'Bind password',
helpArg: 'PASSWD',
default: ''
},
{
names: ['insecure', 'i'],
type: 'bool',
env: 'LDAPJS_TLS_INSECURE',
help: 'Disable SSL certificate verification',
default: false
}
];
var parser = dashdash.createParser({options: opts});
///--- Helpers
function usage(code, message) {
var msg = (message ? message + '\n' : '') +
'Usage: ' + path.basename(process.argv[1]) +
' [OPTIONS] FILTER [ATTRIBUTES...]\n\n' +
parser.help({includeEnv: true});
process.stderr.write(msg + '\n');
process.exit(code);
}
function perror(err) {
if (parsed.debug) {
process.stderr.write(err.stack + '\n');
} else {
process.stderr.write(err.message + '\n');
}
process.exit(1);
}
function EntryFormatter(fp, format) {
this.format = format;
this.started = false;
this.ended = false;
this.fp = fp;
}
EntryFormatter.prototype.write = function write(entry) {
switch (this.format) {
case 'json':
this.fp.write(JSON.stringify(entry.object, null, 2) + '\n');
break;
case 'jsonl':
this.fp.write(JSON.stringify(entry.object) + '\n');
break;
case 'jsona':
this.fp.write((this.started) ? ',\n' : '[\n');
this.started = true;
// pretty-print with indent
this.fp.write(
JSON.stringify(entry.object, null, 2)
.split('\n')
.map(function (line) { return ' ' + line; })
.join('\n'));
break;
default:
throw new Error('invalid output format');
}
};
EntryFormatter.prototype.end = function end() {
if (this.ended) {
return;
}
this.ended = true;
if (this.format === 'jsona') {
this.fp.write('\n]\n');
}
};
///--- Mainline
var parsed;
process.stdout.on('error', function (err) {
if (err.code === 'EPIPE') {
process.exit(0);
} else {
throw err;
}
});
try {
parsed = parser.parse(process.argv);
} catch (e) {
usage(1, e.toString());
}
if (parsed.help)
usage(0);
if (parsed._args.length < 1)
usage(1, 'filter required');
try {
ldap.parseFilter(parsed._args[0]);
} catch (e) {
usage(1, e.message);
}
var logLevel = 'info';
if (parsed.debug)
logLevel = (parsed.debug > 1 ? 'trace' : 'debug');
var formatter = new EntryFormatter(process.stdout, parsed.format);
var log = new Logger({
name: 'ldapjs',
component: 'client',
stream: process.stderr,
level: logLevel
});
var client = ldap.createClient({
url: parsed.url,
log: log,
strictDN: false,
timeout: parsed.timeout || false,
tlsOptions: {
rejectUnauthorized: !parsed.insecure
}
});
client.on('error', function (err) {
perror(err);
});
client.on('timeout', function (req) {
process.stderr.write('Timeout reached\n');
process.exit(1);
});
client.bind(parsed.binddn, parsed.password, function (err, res) {
if (err)
perror(err);
var controls = [];
parsed.control.forEach(function (c) {
controls.push(new ldap.Control({
type: c,
criticality: true
}));
});
if (parsed.persistent) {
var pCtrl = new ldap.PersistentSearchControl({
type: '2.16.840.1.113730.3.4.3',
value: {
changeTypes: 15,
changesOnly: false,
returnECs: true
}
});
controls.push(pCtrl);
}
var req = {
scope: parsed.scope || 'sub',
filter: parsed._args[0],
attributes: parsed._args.length > 1 ? parsed._args.slice(1) : []
};
if (parsed.paged) {
req.paged = {
pageSize: parsed.paged
};
}
client.search(parsed.base, req, controls, function (err, res) {
if (err)
perror(err);
res.on('searchEntry', function (entry) {
formatter.write(entry);
});
res.on('error', function (err) {
formatter.end();
perror(err);
});
res.on('end', function (res) {
formatter.end();
if (res.status !== 0) {
process.stderr.write(ldap.getMessage(res.status) + '\n');
}
client.unbind(function () {
return;
});
});
});
});

1
deps/javascriptlint vendored

@ -1 +0,0 @@
Subproject commit e1bd0abfd424811af469d1ece3af131d95443924

1
deps/jsstyle vendored

@ -1 +0,0 @@
Subproject commit d75b7ca8308be17c80e2b120f2a01d4a0c20d8a8

1
deps/restdown vendored

@ -1 +0,0 @@
Subproject commit 34a843cfce0ff988bf5073706882722a61036786

8
docker-compose.yml Normal file
View File

@ -0,0 +1,8 @@
version: '3'
services:
openldap:
image: docker.pkg.github.com/ldapjs/docker-test-openldap/openldap:latest
ports:
- 389:389
- 636:636

View File

@ -26,19 +26,40 @@ client is:
|---------------|-----------------------------------------------------------|
|url |A valid LDAP URL (proto/host/port only) |
|socketPath |Socket path if using AF\_UNIX sockets |
|log |Bunyan logger instance (Default: built-in instance) |
|log |A compatible logger instance (Default: no-op logger) |
|timeout |Milliseconds client should let operations live for before timing out (Default: Infinity)|
|connectTimeout |Milliseconds client should wait before timing out on TCP connections (Default: OS default)|
|tlsOptions |Additional options passed to TLS connection layer when connecting via `ldaps://` (See: The TLS docs for node.js)|
|idleTimeout |Milliseconds after last activity before client emits idle event|
|strictDN |Force strict DN parsing for client methods (Default is true)|
|reconnect |Try to reconnect when the connection gets lost (Default is false)|
### Note On Logger
A passed in logger is expected to conform to the [Bunyan](https://www.npmjs.com/package/bunyan)
API. Specifically, the logger is expected to have a `child()` method. If a logger
is supplied that does not have such a method, then a shim version is added
that merely returns the passed in logger.
Known compatible loggers are:
+ [Bunyan](https://www.npmjs.com/package/bunyan)
+ [Pino](https://www.npmjs.com/package/pino)
## Connection management
As LDAP is a stateful protocol (as opposed to HTTP), having connections torn
down from underneath you is can be difficult to deal with. Several mechanisms
down from underneath you can be difficult to deal with. Several mechanisms
have been provided to mitigate this trouble.
### Reconnect
You can provide a Boolean option indicating if a reconnect should be tried. For
more sophisticated control, you can provide an Object with the properties
`initialDelay` (default: `100`), `maxDelay` (default: `10000`) and
`failAfter` (default: `Infinity`).
After the reconnect you maybe need to [bind](#bind) again.
## Common patterns
@ -156,9 +177,11 @@ A `Change` object maps to the LDAP protocol of a modify change, and requires you
to set the `operation` and `modification`. The `operation` is a string, and
must be one of:
||replace||Replaces the attribute referenced in `modification`. If the modification has no values, it is equivalent to a delete.||
||add||Adds the attribute value(s) referenced in `modification`. The attribute may or may not already exist.||
||delete||Deletes the attribute (and all values) referenced in `modification`.||
| Operation | Description |
|-----------|-------------|
| replace | Replaces the attribute referenced in `modification`. If the modification has no values, it is equivalent to a delete. |
| add | Adds the attribute value(s) referenced in `modification`. The attribute may or may not already exist. |
| delete | Deletes the attribute (and all values) referenced in `modification`. |
`modification` is just a plain old JS object with the values you want.
@ -375,6 +398,13 @@ Example:
Performs an unbind operation against the LDAP server.
Note that unbind operation is not an opposite operation
for bind. Unbinding results in disconnecting the client
regardless of whether a bind operation was performed.
The `callback` argument is optional as unbind does
not have a response.
Example:
client.unbind(function(err) {

View File

@ -289,7 +289,7 @@ with ldapjs.
var entry = req.toObject().attributes;
if (entry.objectclass.indexOf('unixUser') === -1)
return next(new ldap.ConstraintViolation('entry must be a unixUser'));
return next(new ldap.ConstraintViolationError('entry must be a unixUser'));
var opts = ['-m'];
if (entry.description) {

View File

@ -409,7 +409,7 @@ the following code in as another handler (you'll need a
var entry = req.toObject().attributes;
if (entry.objectclass.indexOf('unixUser') === -1)
return next(new ldap.ConstraintViolation('entry must be a unixUser'));
return next(new ldap.ConstraintViolationError('entry must be a unixUser'));
var opts = ['-m'];
if (entry.description) {
@ -496,7 +496,7 @@ As before, here's a breakdown of the code:
var entry = req.toObject().attributes;
if (entry.objectclass.indexOf('unixUser') === -1)
return next(new ldap.ConstraintViolation('entry must be a unixUser'));
return next(new ldap.ConstraintViolationError('entry must be a unixUser'));
A few new things:

View File

@ -16,10 +16,22 @@ The code to create a new server looks like:
The full list of options is:
||log||You can optionally pass in a bunyan instance the client will use to acquire a logger.||
||log||You can optionally pass in a Bunyan compatible logger instance the client will use to acquire a child logger.||
||certificate||A PEM-encoded X.509 certificate; will cause this server to run in TLS mode.||
||key||A PEM-encoded private key that corresponds to _certificate_ for SSL.||
### Note On Logger
The passed in logger is expected to conform to the Log4j standard API.
Internally, [abstract-logging](https://www.npmjs.com/packages/abstract-logging) is
used to implement the interface. As a result, no log messages will be generated
unless an external logger is supplied.
Known compatible loggers are:
+ [Bunyan](https://www.npmjs.com/package/bunyan)
+ [Pino](https://www.npmjs.com/package/pino)
## Properties on the server object
### maxConnections
@ -27,9 +39,10 @@ The full list of options is:
Set this property to reject connections when the server's connection count gets
high.
### connections (getter only)
### connections (getter only) - DEPRECATED
The number of concurrent connections on the server.
The number of concurrent connections on the server. This property is deprecated,
please use server.getConnections() instead.
### url
@ -53,7 +66,7 @@ available.
Example:
server.listen(389, '127.0.0.1', function() {
console.log(LDAP server listening at: ' + server.url);
console.log('LDAP server listening at: ' + server.url);
});
@ -84,6 +97,13 @@ This file descriptor must have already had the `bind(2)` and `listen(2)` system
calls invoked on it. Additionally, it must be set non-blocking; try
`fcntl(fd, F_SETFL, O_NONBLOCK)`.
## Inspecting server state
### server.getConnections(callback)
The LDAP server API mirrors the [Node.js `server.getConnections` API](https://nodejs.org/dist/latest-v12.x/docs/api/net.html#net_server_getconnections_callback). Callback
should take two arguments err and count.
# Routes
The LDAP server API is meant to be the LDAP-equivalent of the express/restify

View File

@ -1,199 +1,177 @@
var ldap = require('../lib/index');
var ldap = require('../lib/index')
/// --- Shared handlers
///--- Shared handlers
function authorize(req, res, next) {
function authorize (req, res, next) {
/* Any user may search after bind, only cn=root has full power */
var isSearch = (req instanceof ldap.SearchRequest);
if (!req.connection.ldap.bindDN.equals('cn=root') && !isSearch)
return next(new ldap.InsufficientAccessRightsError());
var isSearch = (req instanceof ldap.SearchRequest)
if (!req.connection.ldap.bindDN.equals('cn=root') && !isSearch) { return next(new ldap.InsufficientAccessRightsError()) }
return next();
return next()
}
/// --- Globals
///--- Globals
var SUFFIX = 'o=smartdc';
var db = {};
var server = ldap.createServer();
var SUFFIX = 'o=smartdc'
var db = {}
var server = ldap.createServer()
server.bind('cn=root', function (req, res, next) {
if (req.dn.toString() !== 'cn=root' || req.credentials !== 'secret')
return next(new ldap.InvalidCredentialsError());
if (req.dn.toString() !== 'cn=root' || req.credentials !== 'secret') { return next(new ldap.InvalidCredentialsError()) }
res.end();
return next();
});
res.end()
return next()
})
server.add(SUFFIX, authorize, function (req, res, next) {
var dn = req.dn.toString();
var dn = req.dn.toString()
if (db[dn])
return next(new ldap.EntryAlreadyExistsError(dn));
if (db[dn]) { return next(new ldap.EntryAlreadyExistsError(dn)) }
db[dn] = req.toObject().attributes;
res.end();
return next();
});
db[dn] = req.toObject().attributes
res.end()
return next()
})
server.bind(SUFFIX, function (req, res, next) {
var dn = req.dn.toString();
if (!db[dn])
return next(new ldap.NoSuchObjectError(dn));
var dn = req.dn.toString()
if (!db[dn]) { return next(new ldap.NoSuchObjectError(dn)) }
if (!db[dn].userpassword)
return next(new ldap.NoSuchAttributeError('userPassword'));
if (!db[dn].userpassword) { return next(new ldap.NoSuchAttributeError('userPassword')) }
if (db[dn].userpassword.indexOf(req.credentials) === -1)
return next(new ldap.InvalidCredentialsError());
if (db[dn].userpassword.indexOf(req.credentials) === -1) { return next(new ldap.InvalidCredentialsError()) }
res.end();
return next();
});
res.end()
return next()
})
server.compare(SUFFIX, authorize, function (req, res, next) {
var dn = req.dn.toString();
if (!db[dn])
return next(new ldap.NoSuchObjectError(dn));
var dn = req.dn.toString()
if (!db[dn]) { return next(new ldap.NoSuchObjectError(dn)) }
if (!db[dn][req.attribute])
return next(new ldap.NoSuchAttributeError(req.attribute));
if (!db[dn][req.attribute]) { return next(new ldap.NoSuchAttributeError(req.attribute)) }
var matches = false;
var vals = db[dn][req.attribute];
var matches = false
var vals = db[dn][req.attribute]
for (var i = 0; i < vals.length; i++) {
if (vals[i] === req.value) {
matches = true;
break;
matches = true
break
}
}
res.end(matches);
return next();
});
res.end(matches)
return next()
})
server.del(SUFFIX, authorize, function (req, res, next) {
var dn = req.dn.toString();
if (!db[dn])
return next(new ldap.NoSuchObjectError(dn));
var dn = req.dn.toString()
if (!db[dn]) { return next(new ldap.NoSuchObjectError(dn)) }
delete db[dn];
delete db[dn]
res.end();
return next();
});
res.end()
return next()
})
server.modify(SUFFIX, authorize, function (req, res, next) {
var dn = req.dn.toString();
if (!req.changes.length)
return next(new ldap.ProtocolError('changes required'));
if (!db[dn])
return next(new ldap.NoSuchObjectError(dn));
var dn = req.dn.toString()
if (!req.changes.length) { return next(new ldap.ProtocolError('changes required')) }
if (!db[dn]) { return next(new ldap.NoSuchObjectError(dn)) }
var entry = db[dn];
var entry = db[dn]
let mod
for (var i = 0; i < req.changes.length; i++) {
mod = req.changes[i].modification;
mod = req.changes[i].modification
switch (req.changes[i].operation) {
case 'replace':
if (!entry[mod.type])
return next(new ldap.NoSuchAttributeError(mod.type));
case 'replace':
if (!entry[mod.type]) { return next(new ldap.NoSuchAttributeError(mod.type)) }
if (!mod.vals || !mod.vals.length) {
delete entry[mod.type];
} else {
entry[mod.type] = mod.vals;
}
if (!mod.vals || !mod.vals.length) {
delete entry[mod.type]
} else {
entry[mod.type] = mod.vals
}
break;
break
case 'add':
if (!entry[mod.type]) {
entry[mod.type] = mod.vals;
} else {
mod.vals.forEach(function (v) {
if (entry[mod.type].indexOf(v) === -1)
entry[mod.type].push(v);
});
}
case 'add':
if (!entry[mod.type]) {
entry[mod.type] = mod.vals
} else {
mod.vals.forEach(function (v) {
if (entry[mod.type].indexOf(v) === -1) { entry[mod.type].push(v) }
})
}
break;
break
case 'delete':
if (!entry[mod.type])
return next(new ldap.NoSuchAttributeError(mod.type));
case 'delete':
if (!entry[mod.type]) { return next(new ldap.NoSuchAttributeError(mod.type)) }
delete entry[mod.type];
delete entry[mod.type]
break;
break
}
}
res.end();
return next();
});
res.end()
return next()
})
server.search(SUFFIX, authorize, function (req, res, next) {
var dn = req.dn.toString();
if (!db[dn])
return next(new ldap.NoSuchObjectError(dn));
var dn = req.dn.toString()
if (!db[dn]) { return next(new ldap.NoSuchObjectError(dn)) }
var scopeCheck;
var scopeCheck
switch (req.scope) {
case 'base':
if (req.filter.matches(db[dn])) {
res.send({
dn: dn,
attributes: db[dn]
});
}
case 'base':
if (req.filter.matches(db[dn])) {
res.send({
dn: dn,
attributes: db[dn]
})
}
res.end();
return next();
res.end()
return next()
case 'one':
scopeCheck = function (k) {
if (req.dn.equals(k))
return true;
case 'one':
scopeCheck = function (k) {
if (req.dn.equals(k)) { return true }
var parent = ldap.parseDN(k).parent();
return (parent ? parent.equals(req.dn) : false);
};
break;
var parent = ldap.parseDN(k).parent()
return (parent ? parent.equals(req.dn) : false)
}
break
case 'sub':
scopeCheck = function (k) {
return (req.dn.equals(k) || req.dn.parentOf(k));
};
case 'sub':
scopeCheck = function (k) {
return (req.dn.equals(k) || req.dn.parentOf(k))
}
break;
break
}
Object.keys(db).forEach(function (key) {
if (!scopeCheck(key))
return;
if (!scopeCheck(key)) { return }
if (req.filter.matches(db[key])) {
res.send({
dn: key,
attributes: db[key]
});
})
}
});
})
res.end();
return next();
});
res.end()
return next()
})
///--- Fire it up
/// --- Fire it up
server.listen(1389, function () {
console.log('LDAP server up at: %s', server.url);
});
console.log('LDAP server up at: %s', server.url)
})

View File

@ -1,61 +1,54 @@
// Copyright 2015 Joyent, Inc.
var assert = require('assert');
var util = require('util');
var assert = require('assert')
var util = require('util')
var isDN = require('./dn').DN.isDN;
var isAttribute = require('./attribute').isAttribute;
var isDN = require('./dn').DN.isDN
var isAttribute = require('./attribute').isAttribute
///--- Helpers
/// --- Helpers
// Copied from mcavage/node-assert-plus
function _assert(arg, type, name) {
name = name || type;
function _assert (arg, type, name) {
name = name || type
throw new assert.AssertionError({
message: util.format('%s (%s) required', name, type),
actual: typeof (arg),
expected: type,
operator: '===',
stackStartFunction: _assert.caller
});
})
}
/// --- API
///--- API
function stringDN(input, name) {
if (isDN(input) || typeof (input) === 'string')
return;
_assert(input, 'DN or string', name);
function stringDN (input, name) {
if (isDN(input) || typeof (input) === 'string') { return }
_assert(input, 'DN or string', name)
}
function optionalStringDN(input, name) {
if (input === undefined || isDN(input) || typeof (input) === 'string')
return;
_assert(input, 'DN or string', name);
function optionalStringDN (input, name) {
if (input === undefined || isDN(input) || typeof (input) === 'string') { return }
_assert(input, 'DN or string', name)
}
function optionalDN(input, name) {
if (input !== undefined && !isDN(input))
_assert(input, 'DN', name);
function optionalDN (input, name) {
if (input !== undefined && !isDN(input)) { _assert(input, 'DN', name) }
}
function optionalArrayOfAttribute(input, name) {
if (input === undefined)
return;
function optionalArrayOfAttribute (input, name) {
if (input === undefined) { return }
if (!Array.isArray(input) ||
input.some(function (v) { return !isAttribute(v); })) {
_assert(input, 'array of Attribute', name);
input.some(function (v) { return !isAttribute(v) })) {
_assert(input, 'array of Attribute', name)
}
}
///--- Exports
/// --- Exports
module.exports = {
stringDN: stringDN,
optionalStringDN: optionalStringDN,
optionalDN: optionalDN,
optionalArrayOfAttribute: optionalArrayOfAttribute
};
}

View File

@ -1,174 +1,160 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var assert = require('assert')
var asn1 = require('asn1');
var asn1 = require('asn1')
var Protocol = require('./protocol');
var Protocol = require('./protocol')
/// --- API
///--- API
function Attribute(options) {
function Attribute (options) {
if (options) {
if (typeof (options) !== 'object')
throw new TypeError('options must be an object');
if (options.type && typeof (options.type) !== 'string')
throw new TypeError('options.type must be a string');
if (typeof (options) !== 'object') { throw new TypeError('options must be an object') }
if (options.type && typeof (options.type) !== 'string') { throw new TypeError('options.type must be a string') }
} else {
options = {};
options = {}
}
this.type = options.type || '';
this._vals = [];
this.type = options.type || ''
this._vals = []
if (options.vals !== undefined && options.vals !== null)
this.vals = options.vals;
if (options.vals !== undefined && options.vals !== null) { this.vals = options.vals }
}
module.exports = Attribute;
module.exports = Attribute
Object.defineProperties(Attribute.prototype, {
buffers: {
get: function getBuffers() {
return this._vals;
get: function getBuffers () {
return this._vals
},
configurable: false
},
json: {
get: function getJson() {
get: function getJson () {
return {
type: this.type,
vals: this.vals
};
}
},
configurable: false
},
vals: {
get: function getVals() {
var eType = _bufferEncoding(this.type);
get: function getVals () {
var eType = _bufferEncoding(this.type)
return this._vals.map(function (v) {
return v.toString(eType);
});
return v.toString(eType)
})
},
set: function setVals(vals) {
var self = this;
this._vals = [];
set: function setVals (vals) {
var self = this
this._vals = []
if (Array.isArray(vals)) {
vals.forEach(function (v) {
self.addValue(v);
});
self.addValue(v)
})
} else {
self.addValue(vals);
self.addValue(vals)
}
},
configurable: false
}
});
})
Attribute.prototype.addValue = function addValue(val) {
Attribute.prototype.addValue = function addValue (val) {
if (Buffer.isBuffer(val)) {
this._vals.push(val);
this._vals.push(val)
} else {
this._vals.push(new Buffer(val + '', _bufferEncoding(this.type)));
this._vals.push(Buffer.from(val + '', _bufferEncoding(this.type)))
}
};
}
/* BEGIN JSSTYLED */
Attribute.compare = function compare(a, b) {
Attribute.compare = function compare (a, b) {
if (!(Attribute.isAttribute(a)) || !(Attribute.isAttribute(b))) {
throw new TypeError('can only compare Attributes');
throw new TypeError('can only compare Attributes')
}
if (a.type < b.type) return -1;
if (a.type > b.type) return 1;
if (a.vals.length < b.vals.length) return -1;
if (a.vals.length > b.vals.length) return 1;
if (a.type < b.type) return -1
if (a.type > b.type) return 1
if (a.vals.length < b.vals.length) return -1
if (a.vals.length > b.vals.length) return 1
for (var i = 0; i < a.vals.length; i++) {
if (a.vals[i] < b.vals[i]) return -1;
if (a.vals[i] > b.vals[i]) return 1;
if (a.vals[i] < b.vals[i]) return -1
if (a.vals[i] > b.vals[i]) return 1
}
return 0;
};
return 0
}
/* END JSSTYLED */
Attribute.prototype.parse = function parse (ber) {
assert.ok(ber)
Attribute.prototype.parse = function parse(ber) {
assert.ok(ber);
ber.readSequence();
this.type = ber.readString();
ber.readSequence()
this.type = ber.readString()
if (ber.peek() === Protocol.LBER_SET) {
if (ber.readSequence(Protocol.LBER_SET)) {
var end = ber.offset + ber.length;
while (ber.offset < end)
this._vals.push(ber.readString(asn1.Ber.OctetString, true));
var end = ber.offset + ber.length
while (ber.offset < end) { this._vals.push(ber.readString(asn1.Ber.OctetString, true)) }
}
}
return true;
};
return true
}
Attribute.prototype.toBer = function toBer (ber) {
assert.ok(ber)
Attribute.prototype.toBer = function toBer(ber) {
assert.ok(ber);
ber.startSequence();
ber.writeString(this.type);
ber.startSequence(Protocol.LBER_SET);
ber.startSequence()
ber.writeString(this.type)
ber.startSequence(Protocol.LBER_SET)
if (this._vals.length) {
this._vals.forEach(function (b) {
ber.writeByte(asn1.Ber.OctetString);
ber.writeLength(b.length);
for (var i = 0; i < b.length; i++)
ber.writeByte(b[i]);
});
ber.writeByte(asn1.Ber.OctetString)
ber.writeLength(b.length)
for (var i = 0; i < b.length; i++) { ber.writeByte(b[i]) }
})
} else {
ber.writeStringArray([]);
ber.writeStringArray([])
}
ber.endSequence();
ber.endSequence();
return ber;
};
ber.endSequence()
ber.endSequence()
return ber
}
Attribute.prototype.toString = function () {
return JSON.stringify(this.json);
};
return JSON.stringify(this.json)
}
Attribute.toBer = function (attr, ber) {
return Attribute.prototype.toBer.call(attr, ber);
};
return Attribute.prototype.toBer.call(attr, ber)
}
Attribute.isAttribute = function isAttribute(attr) {
Attribute.isAttribute = function isAttribute (attr) {
if (!attr || typeof (attr) !== 'object') {
return false;
return false
}
if (attr instanceof Attribute) {
return true;
return true
}
if ((typeof (attr.toBer) === 'function') &&
(typeof (attr.type) === 'string') &&
(Array.isArray(attr.vals)) &&
(attr.vals.filter(function (item) {
return (typeof (item) === 'string' ||
Buffer.isBuffer(item));
}).length === attr.vals.length)) {
return true;
return (typeof (item) === 'string' ||
Buffer.isBuffer(item))
}).length === attr.vals.length)) {
return true
}
return false;
};
function _bufferEncoding(type) {
/* JSSTYLED */
return /;binary$/.test(type) ? 'base64' : 'utf8';
return false
}
function _bufferEncoding (type) {
/* JSSTYLED */
return /;binary$/.test(type) ? 'base64' : 'utf8'
}

View File

@ -1,129 +1,127 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var assert = require('assert-plus')
var Attribute = require('./attribute');
var Protocol = require('./protocol');
var Attribute = require('./attribute')
// var Protocol = require('./protocol')
/// --- API
///--- API
function Change(options) {
function Change (options) {
if (options) {
assert.object(options);
assert.optionalString(options.operation);
assert.object(options)
assert.optionalString(options.operation)
} else {
options = {};
options = {}
}
this._modification = false;
this.operation = options.operation || options.type || 'add';
this.modification = options.modification || {};
this._modification = false
this.operation = options.operation || options.type || 'add'
this.modification = options.modification || {}
}
Object.defineProperties(Change.prototype, {
operation: {
get: function getOperation() {
get: function getOperation () {
switch (this._operation) {
case 0x00: return 'add';
case 0x01: return 'delete';
case 0x02: return 'replace';
default:
throw new Error('0x' + this._operation.toString(16) + ' is invalid');
case 0x00: return 'add'
case 0x01: return 'delete'
case 0x02: return 'replace'
default:
throw new Error('0x' + this._operation.toString(16) + ' is invalid')
}
},
set: function setOperation(val) {
assert.string(val);
set: function setOperation (val) {
assert.string(val)
switch (val.toLowerCase()) {
case 'add':
this._operation = 0x00;
break;
case 'delete':
this._operation = 0x01;
break;
case 'replace':
this._operation = 0x02;
break;
default:
throw new Error('Invalid operation type: 0x' + val.toString(16));
case 'add':
this._operation = 0x00
break
case 'delete':
this._operation = 0x01
break
case 'replace':
this._operation = 0x02
break
default:
throw new Error('Invalid operation type: 0x' + val.toString(16))
}
},
configurable: false
},
modification: {
get: function getModification() {
return this._modification;
get: function getModification () {
return this._modification
},
set: function setModification(val) {
set: function setModification (val) {
if (Attribute.isAttribute(val)) {
this._modification = val;
return;
this._modification = val
return
}
// Does it have an attribute-like structure
if (Object.keys(val).length == 2 &&
if (Object.keys(val).length === 2 &&
typeof (val.type) === 'string' &&
Array.isArray(val.vals)) {
this._modification = new Attribute({
type: val.type,
vals: val.vals
});
return;
})
return
}
var keys = Object.keys(val);
var keys = Object.keys(val)
if (keys.length > 1) {
throw new Error('Only one attribute per Change allowed');
throw new Error('Only one attribute per Change allowed')
} else if (keys.length === 0) {
return;
return
}
var k = keys[0];
var _attr = new Attribute({type: k});
var k = keys[0]
var _attr = new Attribute({ type: k })
if (Array.isArray(val[k])) {
val[k].forEach(function (v) {
_attr.addValue(v.toString());
});
} else {
_attr.addValue(val[k].toString());
_attr.addValue(v.toString())
})
} else if (Buffer.isBuffer(val[k])) {
_attr.addValue(val[k])
} else if (val[k] !== undefined && val[k] !== null) {
_attr.addValue(val[k].toString())
}
this._modification = _attr;
this._modification = _attr
},
configurable: false
},
json: {
get: function getJSON() {
get: function getJSON () {
return {
operation: this.operation,
modification: this._modification ? this._modification.json : {}
};
}
},
configurable: false
}
});
})
Change.isChange = function isChange(change) {
Change.isChange = function isChange (change) {
if (!change || typeof (change) !== 'object') {
return false;
return false
}
if ((change instanceof Change) ||
((typeof (change.toBer) === 'function') &&
(change.modification !== undefined) &&
(change.operation !== undefined))) {
return true;
return true
}
return false;
};
return false
}
Change.compare = function (a, b) {
if (!Change.isChange(a) || !Change.isChange(b))
throw new TypeError('can only compare Changes');
if (!Change.isChange(a) || !Change.isChange(b)) { throw new TypeError('can only compare Changes') }
if (a.operation < b.operation)
return -1;
if (a.operation > b.operation)
return 1;
if (a.operation < b.operation) { return -1 }
if (a.operation > b.operation) { return 1 }
return Attribute.compare(a.modification, b.modification);
};
return Attribute.compare(a.modification, b.modification)
}
/**
* Apply a Change to properties of an object.
@ -132,86 +130,83 @@ Change.compare = function (a, b) {
* @param {Object} obj the object to apply it to.
* @param {Boolean} scalar convert single-item arrays to scalars. Default: false
*/
Change.apply = function apply(change, obj, scalar) {
assert.string(change.operation);
assert.string(change.modification.type);
assert.ok(Array.isArray(change.modification.vals));
assert.object(obj);
Change.apply = function apply (change, obj, scalar) {
assert.string(change.operation)
assert.string(change.modification.type)
assert.ok(Array.isArray(change.modification.vals))
assert.object(obj)
var type = change.modification.type;
var vals = change.modification.vals;
var data = obj[type];
var type = change.modification.type
var vals = change.modification.vals
var data = obj[type]
if (data !== undefined) {
if (!Array.isArray(data)) {
data = [data];
data = [data]
}
} else {
data = [];
data = []
}
switch (change.operation) {
case 'replace':
if (vals.length === 0) {
case 'replace':
if (vals.length === 0) {
// replace empty is a delete
delete obj[type];
return obj;
} else {
data = vals;
}
break;
case 'add':
delete obj[type]
return obj
} else {
data = vals
}
break
case 'add':
// add only new unique entries
var newValues = vals.filter(function (entry) {
return (data.indexOf(entry) === -1);
});
data = data.concat(newValues);
break;
case 'delete':
data = data.filter(function (entry) {
return (vals.indexOf(entry) === -1);
});
if (data.length === 0) {
var newValues = vals.filter(function (entry) {
return (data.indexOf(entry) === -1)
})
data = data.concat(newValues)
break
case 'delete':
data = data.filter(function (entry) {
return (vals.indexOf(entry) === -1)
})
if (data.length === 0) {
// Erase the attribute if empty
delete obj[type];
return obj;
}
break;
default:
break;
delete obj[type]
return obj
}
break
default:
break
}
if (scalar && data.length === 1) {
// store single-value outputs as scalars, if requested
obj[type] = data[0];
obj[type] = data[0]
} else {
obj[type] = data;
obj[type] = data
}
return obj;
};
return obj
}
Change.prototype.parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.readSequence();
this._operation = ber.readEnumeration();
this._modification = new Attribute();
this._modification.parse(ber);
return true;
};
ber.readSequence()
this._operation = ber.readEnumeration()
this._modification = new Attribute()
this._modification.parse(ber)
return true
}
Change.prototype.toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.startSequence();
ber.writeEnumeration(this._operation);
ber = this._modification.toBer(ber);
ber.endSequence();
ber.startSequence()
ber.writeEnumeration(this._operation)
ber = this._modification.toBer(ber)
ber.endSequence()
return ber;
};
return ber
}
/// --- Exports
///--- Exports
module.exports = Change;
module.exports = Change

File diff suppressed because it is too large Load Diff

7
lib/client/constants.js Normal file
View File

@ -0,0 +1,7 @@
'use strict'
module.exports = {
// https://tools.ietf.org/html/rfc4511#section-4.1.1
// Message identifiers are an integer between (0, maxint).
MAX_MSGID: Math.pow(2, 31) - 1
}

View File

@ -1,56 +1,23 @@
// Copyright 2012 Mark Cavage, Inc. All rights reserved.
'use strict'
var assert = require('assert');
var Logger = require('bunyan');
var Client = require('./client');
///--- Globals
var DEF_LOG = new Logger({
name: 'ldapjs',
component: 'client',
stream: process.stderr,
serializers: Logger.stdSerializers
});
///--- Functions
function xor() {
var b = false;
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] && !b) {
b = true;
} else if (arguments[i] && b) {
return false;
}
}
return b;
}
///--- Exports
const logger = require('../logger')
const Client = require('./client')
module.exports = {
Client: Client,
createClient: function createClient(options) {
if (typeof (options) !== 'object')
throw new TypeError('options (object) required');
if (options.url && typeof (options.url) !== 'string')
throw new TypeError('options.url (string) required');
if (options.socketPath && typeof (options.socketPath) !== 'string')
throw new TypeError('options.socketPath must be a string');
if (!xor(options.url, options.socketPath))
throw new TypeError('options.url ^ options.socketPath (String) required');
if (!options.log)
options.log = DEF_LOG;
if (typeof (options.log) !== 'object')
throw new TypeError('options.log must be an object');
createClient: function createClient (options) {
if (isObject(options) === false) throw TypeError('options (object) required')
if (options.url && typeof options.url !== 'string') throw TypeError('options.url (string) required')
if (options.socketPath && typeof options.socketPath !== 'string') throw TypeError('options.socketPath must be a string')
if ((options.url && options.socketPath) || !(options.url || options.socketPath)) throw TypeError('options.url ^ options.socketPath (String) required')
if (!options.log) options.log = logger
if (isObject(options.log) !== true) throw TypeError('options.log must be an object')
if (!options.log.child) options.log.child = function () { return options.log }
return new Client(options);
return new Client(options)
}
};
}
function isObject (input) {
return Object.prototype.toString.apply(input) === '[object Object]'
}

View File

@ -0,0 +1,25 @@
'use strict'
const { MAX_MSGID } = require('../constants')
/**
* Compare a reference id with another id to determine "greater than or equal"
* between the two values according to a sliding window.
*
* @param {integer} ref
* @param {integer} comp
*
* @returns {boolean} `true` if the `comp` value is >= to the `ref` value
* within the computed window, otherwise `false`.
*/
module.exports = function geWindow (ref, comp) {
let max = ref + Math.floor(MAX_MSGID / 2)
const min = ref
if (max >= MAX_MSGID) {
// Handle roll-over
max = max - MAX_MSGID - 1
return ((comp <= max) || (comp >= min))
} else {
return ((comp <= max) && (comp >= min))
}
}

View File

@ -0,0 +1,23 @@
'use strict'
const { MAX_MSGID } = require('../constants')
/**
* Returns a function that generates message identifiers. According to RFC 4511
* the identifers should be `(0, MAX_MSGID)`. The returned function handles
* this and wraps around when the maximum has been reached.
*
* @param {integer} [start=0] Starting number in the identifier sequence.
*
* @returns {function} This function accepts no parameters and returns an
* increasing sequence identifier each invocation until it reaches the maximum
* identifier. At this point the sequence starts over.
*/
module.exports = function idGeneratorFactory (start = 0) {
let currentID = start
return function nextID () {
const nextID = currentID + 1
currentID = (nextID >= MAX_MSGID) ? 1 : nextID
return currentID
}
}

View File

@ -0,0 +1,151 @@
'use strict'
const idGeneratorFactory = require('./id-generator')
const purgeAbandoned = require('./purge-abandoned')
/**
* Returns a message tracker object that keeps track of which message
* identifiers correspond to which message handlers. Also handles keeping track
* of abandoned messages.
*
* @param {object} options
* @param {string} options.id An identifier for the tracker.
* @param {object} options.parser An object that will be used to parse messages.
*
* @returns {MessageTracker}
*/
module.exports = function messageTrackerFactory (options) {
if (Object.prototype.toString.call(options) !== '[object Object]') {
throw Error('options object is required')
}
if (!options.id || typeof options.id !== 'string') {
throw Error('options.id string is required')
}
if (!options.parser || Object.prototype.toString.call(options.parser) !== '[object Object]') {
throw Error('options.parser object is required')
}
let currentID = 0
const nextID = idGeneratorFactory()
const messages = new Map()
const abandoned = new Map()
/**
* @typedef {object} MessageTracker
* @property {string} id The identifier of the tracker as supplied via the options.
* @property {object} parser The parser object given by the the options.
*/
const tracker = {
id: options.id,
parser: options.parser
}
/**
* Count of messages awaiting response.
*
* @alias pending
* @memberof! MessageTracker#
*/
Object.defineProperty(tracker, 'pending', {
get () {
return messages.size
}
})
/**
* Move a specific message to the abanded track.
*
* @param {integer} msgID The identifier for the message to move.
*
* @memberof MessageTracker
* @method abandon
*/
tracker.abandon = function abandonMessage (msgID) {
if (messages.has(msgID) === false) return false
abandoned.set(msgID, {
age: currentID,
cb: messages.get(msgID)
})
return messages.delete(msgID)
}
/**
* Retrieves the message handler for a message. Removes abandoned messages
* that have been given time to be resolved.
*
* @param {integer} msgID The identifier for the message to get the handler for.
*
* @memberof MessageTracker
* @method fetch
*/
tracker.fetch = function fetchMessage (msgID) {
const messageCB = messages.get(msgID)
if (messageCB) {
purgeAbandoned(msgID, abandoned)
return messageCB
}
// We sent an abandon request but the server either wasn't able to process
// it or has not received it yet. Therefore, we received a response for the
// abandoned message. So we must return the abandoned message's callback
// to be processed normally.
const abandonedMsg = abandoned.get(msgID)
if (abandonedMsg) {
return abandonedMsg.cb
}
return null
}
/**
* Removes all message tracks, cleans up the abandoned track, and invokes
* a callback for each message purged.
*
* @param {function} cb A function with the signature `(msgID, handler)`.
*
* @memberof MessageTracker
* @method purge
*/
tracker.purge = function purgeMessages (cb) {
messages.forEach((val, key) => {
purgeAbandoned(key, abandoned)
tracker.remove(key)
cb(key, val)
})
}
/**
* Removes a message from all tracking.
*
* @param {integer} msgID The identifier for the message to remove from tracking.
*
* @memberof MessageTracker
* @method remove
*/
tracker.remove = function removeMessage (msgID) {
if (messages.delete(msgID) === false) {
abandoned.delete(msgID)
}
}
/**
* Add a message handler to be tracked.
*
* @param {object} message The message object to be tracked. This object will
* have a new property added to it: `messageID`.
* @param {function} callback The handler for the message.
*
* @memberof MessageTracker
* @method track
*/
tracker.track = function trackMessage (message, callback) {
currentID = nextID()
// This side effect is not ideal but the client doesn't attach the tracker
// to itself until after the `.connect` method has fired. If this can be
// refactored later, then we can possibly get rid of this side effect.
message.messageID = currentID
messages.set(currentID, callback)
}
return tracker
}

View File

@ -0,0 +1,34 @@
'use strict'
const { AbandonedError } = require('../../errors')
const geWindow = require('./ge-window')
/**
* Given a `msgID` and a set of `abandoned` messages, remove any abandoned
* messages that existed _prior_ to the specified `msgID`. For example, let's
* assume the server has sent 3 messages:
*
* 1. A search message.
* 2. An abandon message for the search message.
* 3. A new search message.
*
* When the response for message #1 comes in, if it does, it will be processed
* normally due to the specification. Message #2 will not receive a response, or
* if the server does send one since the spec sort of allows it, we won't do
* anything with it because we just discard that listener. Now the response
* for message #3 comes in. At this point, we will issue a purge of responses
* by passing in `msgID = 3`. This result is that we will remove the tracking
* for message #1.
*
* @param {integer} msgID An upper bound for the messages to be purged.
* @param {Map} abandoned A set of abandoned messages. Each message is an object
* `{ age: <id>, cb: <func> }` where `age` was the current message id when the
* abandon message was sent.
*/
module.exports = function purgeAbandoned (msgID, abandoned) {
abandoned.forEach((val, key) => {
if (geWindow(val.age, msgID) === false) return
val.cb(new AbandonedError('client request abandoned'))
abandoned.delete(key)
})
}

View File

@ -0,0 +1,36 @@
'use strict'
/**
* Adds requests to the queue. If a timeout has been added to the queue then
* this will freeze the queue with the newly added item, flush it, and then
* unfreeze it when the queue has been cleared.
*
* @param {object} message An LDAP message object.
* @param {object} expect An expectation object.
* @param {object} emitter An event emitter or `null`.
* @param {function} cb A callback to invoke when the request is finished.
*
* @returns {boolean} `true` if the requested was queued. `false` if the queue
* is not accepting any requests.
*/
module.exports = function enqueue (message, expect, emitter, cb) {
if (this._queue.length >= this.size || this._frozen) {
return false
}
this._queue.add({ message, expect, emitter, cb })
if (this.timeout === 0) return true
if (this._timer === null) return true
// A queue can have a specified time allotted for it to be cleared. If that
// time has been reached, reject new entries until the queue has been cleared.
this._timer = setTimeout(queueTimeout.bind(this), this.timeout)
return true
function queueTimeout () {
this.freeze()
this.purge()
}
}

View File

@ -0,0 +1,24 @@
'use strict'
/**
* Invokes all requests in the queue by passing them to the supplied callback
* function and then clears all items from the queue.
*
* @param {function} cb A function used to handle the requests.
*/
module.exports = function flush (cb) {
if (this._timer) {
clearTimeout(this._timer)
this._timer = null
}
// We must get a local copy of the queue and clear it before iterating it.
// The client will invoke this flush function _many_ times. If we try to
// iterate it without a local copy and clearing first then we will overflow
// the stack.
const requests = Array.from(this._queue.values())
this._queue.clear()
for (const req of requests) {
cb(req.message, req.expect, req.emitter, req.cb)
}
}

View File

@ -0,0 +1,39 @@
'use strict'
const enqueue = require('./enqueue')
const flush = require('./flush')
const purge = require('./purge')
/**
* Builds a request queue object and returns it.
*
* @param {object} [options]
* @param {integer} [options.size] Maximum size of the request queue. Must be
* a number greater than `0` if supplied. Default: `Infinity`.
* @param {integer} [options.timeout] Time in milliseconds a queue has to
* complete the requests it contains.
*
* @returns {object} A queue instance.
*/
module.exports = function requestQueueFactory (options) {
const opts = Object.assign({}, options)
const q = {
size: (opts.size > 0) ? opts.size : Infinity,
timeout: (opts.timeout > 0) ? opts.timeout : 0,
_queue: new Set(),
_timer: null,
_frozen: false
}
q.enqueue = enqueue.bind(q)
q.flush = flush.bind(q)
q.purge = purge.bind(q)
q.freeze = function freeze () {
this._frozen = true
}
q.thaw = function thaw () {
this._frozen = false
}
return q
}

View File

@ -0,0 +1,12 @@
'use strict'
const { TimeoutError } = require('../../errors')
/**
* Flushes the queue by rejecting all pending requests with a timeout error.
*/
module.exports = function purge () {
this.flush(function flushCB (a, b, c, cb) {
cb(new TimeoutError('request queue timeout'))
})
}

View File

@ -1,18 +1,16 @@
// Copyright 2014 Joyent, Inc. All rights reserved.
'use strict'
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var EventEmitter = require('events').EventEmitter
var util = require('util')
var assert = require('assert-plus');
var assert = require('assert-plus')
var dn = require('../dn');
var messages = require('../messages/index');
var Protocol = require('../protocol');
var PagedControl = require('../controls/paged_results_control.js');
///--- API
// var dn = require('../dn')
// var messages = require('../messages/index')
// var Protocol = require('../protocol')
var PagedControl = require('../controls/paged_results_control.js')
/// --- API
/**
* Handler object for paged search operations.
@ -33,140 +31,140 @@ var PagedControl = require('../controls/paged_results_control.js');
* able to emit 'end'.
* 3. search - Emitted as an internal event to trigger another client search.
*/
function SearchPager(opts) {
assert.object(opts);
assert.func(opts.callback);
assert.number(opts.pageSize);
function SearchPager (opts) {
assert.object(opts)
assert.func(opts.callback)
assert.number(opts.pageSize)
EventEmitter.call(this, {});
EventEmitter.call(this, {})
this.callback = opts.callback;
this.controls = opts.controls;
this.pageSize = opts.pageSize;
this.pagePause = opts.pagePause;
this.callback = opts.callback
this.controls = opts.controls
this.pageSize = opts.pageSize
this.pagePause = opts.pagePause
this.controls.forEach(function (control) {
if (control.type === PagedControl.OID) {
// The point of using SearchPager is not having to do this.
// Toss an error if the pagedResultsControl is present
throw new Error('redundant pagedResultControl');
throw new Error('redundant pagedResultControl')
}
});
})
this.finished = false;
this.started = false;
this.finished = false
this.started = false
var emitter = new EventEmitter();
emitter.on('searchEntry', this.emit.bind(this, 'searchEntry'));
emitter.on('end', this._onEnd.bind(this));
emitter.on('error', this._onError.bind(this));
this.childEmitter = emitter;
var emitter = new EventEmitter()
emitter.on('searchEntry', this.emit.bind(this, 'searchEntry'))
emitter.on('end', this._onEnd.bind(this))
emitter.on('error', this._onError.bind(this))
this.childEmitter = emitter
}
util.inherits(SearchPager, EventEmitter);
module.exports = SearchPager;
util.inherits(SearchPager, EventEmitter)
module.exports = SearchPager
/**
* Start the paged search.
*/
SearchPager.prototype.begin = function begin() {
SearchPager.prototype.begin = function begin () {
// Starting first page
this._nextPage(null);
};
this._nextPage(null)
}
SearchPager.prototype._onEnd = function _onEnd(res) {
var self = this;
var cookie = null;
SearchPager.prototype._onEnd = function _onEnd (res) {
var self = this
var cookie = null
res.controls.forEach(function (control) {
if (control.type === PagedControl.OID) {
cookie = control.value.cookie;
cookie = control.value.cookie
}
});
})
// Pass a noop callback by default for page events
var nullCb = function () { };
var nullCb = function () { }
if (cookie === null) {
// paged search not supported
this.finished = true;
this.emit('page', res, nullCb);
var err = new Error('missing paged control');
err.name = 'PagedError';
this.finished = true
this.emit('page', res, nullCb)
var err = new Error('missing paged control')
err.name = 'PagedError'
if (this.listeners('pageError').length > 0) {
this.emit('pageError', err);
this.emit('pageError', err)
// If the consumer as subscribed to pageError, SearchPager is absolved
// from deliverying the fault via the 'error' event. Emitting an 'end'
// event after 'error' breaks the contract that the standard client
// provides, so it's only a possibility if 'pageError' is used instead.
this.emit('end', res);
this.emit('end', res)
} else {
this.emit('error', err);
this.emit('error', err)
// No end event possible per explaination above.
}
return;
return
}
if (cookie.length === 0) {
// end of paged results
this.finished = true;
this.emit('page', nullCb);
this.emit('end', res);
this.finished = true
this.emit('page', nullCb)
this.emit('end', res)
} else {
if (this.pagePause) {
// Wait to fetch next page until callback is invoked
// Halt page fetching if called with error
this.emit('page', res, function (err) {
if (!err) {
self._nextPage(cookie);
self._nextPage(cookie)
} else {
// the paged search has been canceled so emit an end
self.emit('end', res);
self.emit('end', res)
}
});
})
} else {
this.emit('page', res, nullCb);
this._nextPage(cookie);
this.emit('page', res, nullCb)
this._nextPage(cookie)
}
}
};
}
SearchPager.prototype._onError = function _onError(err) {
this.finished = true;
this.emit('error', err);
};
SearchPager.prototype._onError = function _onError (err) {
this.finished = true
this.emit('error', err)
}
/**
* Initiate a search for the next page using the returned cookie value.
*/
SearchPager.prototype._nextPage = function _nextPage(cookie) {
var controls = this.controls.slice(0);
SearchPager.prototype._nextPage = function _nextPage (cookie) {
var controls = this.controls.slice(0)
controls.push(new PagedControl({
value: {
size: this.pageSize,
cookie: cookie
}
}));
}))
this.emit('search', controls, this.childEmitter,
this._sendCallback.bind(this));
};
this._sendCallback.bind(this))
}
/**
* Callback provided to the client API for successful transmission.
*/
SearchPager.prototype._sendCallback = function _sendCallback(err, res) {
SearchPager.prototype._sendCallback = function _sendCallback (err, res) {
if (err) {
this.finished = true;
this.finished = true
if (!this.started) {
// EmitSend error during the first page, bail via callback
this.callback(err, null);
this.callback(err, null)
} else {
this.emit('error', err);
this.emit('error', err)
}
} else {
// search successfully send
if (!this.started) {
this.started = true;
this.started = true
// send self as emitter as the client would
this.callback(null, this);
this.callback(null, this)
}
}
};
}

View File

@ -1,67 +1,61 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var asn1 = require('asn1');
// var asn1 = require('asn1')
var Protocol = require('../protocol');
// var Protocol = require('../protocol')
/// --- Globals
///--- Globals
// var Ber = asn1.Ber
var Ber = asn1.Ber;
/// --- API
///--- API
function Control(options) {
assert.optionalObject(options);
options = options || {};
assert.optionalString(options.type);
assert.optionalBool(options.criticality);
function Control (options) {
assert.optionalObject(options)
options = options || {}
assert.optionalString(options.type)
assert.optionalBool(options.criticality)
if (options.value) {
assert.buffer(options.value);
assert.buffer(options.value)
}
this.type = options.type || '';
this.criticality = options.critical || options.criticality || false;
this.value = options.value || null;
this.type = options.type || ''
this.criticality = options.critical || options.criticality || false
this.value = options.value || null
}
Object.defineProperties(Control.prototype, {
json: {
get: function getJson() {
get: function getJson () {
var obj = {
controlType: this.type,
criticality: this.criticality,
controlValue: this.value
};
return (typeof (this._json) === 'function' ? this._json(obj) : obj);
}
return (typeof (this._json) === 'function' ? this._json(obj) : obj)
}
}
});
})
Control.prototype.toBer = function toBer(ber) {
assert.ok(ber);
Control.prototype.toBer = function toBer (ber) {
assert.ok(ber)
ber.startSequence();
ber.writeString(this.type || '');
ber.writeBoolean(this.criticality);
ber.startSequence()
ber.writeString(this.type || '')
ber.writeBoolean(this.criticality)
if (typeof (this._toBer) === 'function') {
this._toBer(ber);
this._toBer(ber)
} else {
if (this.value)
ber.writeString(this.value);
if (this.value) { ber.writeString(this.value) }
}
ber.endSequence();
return;
};
ber.endSequence()
}
Control.prototype.toString = function toString() {
return this.json;
};
Control.prototype.toString = function toString () {
return this.json
}
///--- Exports
module.exports = Control;
/// --- Exports
module.exports = Control

View File

@ -1,89 +1,83 @@
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
var asn1 = require('asn1')
var Control = require('./control');
var Control = require('./control')
/// --- Globals
///--- Globals
var BerReader = asn1.BerReader
var BerWriter = asn1.BerWriter
var BerReader = asn1.BerReader;
var BerWriter = asn1.BerWriter;
/// --- API
///--- API
function EntryChangeNotificationControl(options) {
assert.optionalObject(options);
options = options || {};
options.type = EntryChangeNotificationControl.OID;
function EntryChangeNotificationControl (options) {
assert.optionalObject(options)
options = options || {}
options.type = EntryChangeNotificationControl.OID
if (options.value) {
if (Buffer.isBuffer(options.value)) {
this.parse(options.value);
this.parse(options.value)
} else if (typeof (options.value) === 'object') {
this._value = options.value;
this._value = options.value
} else {
throw new TypeError('options.value must be a Buffer or Object');
throw new TypeError('options.value must be a Buffer or Object')
}
options.value = null;
options.value = null
}
Control.call(this, options);
Control.call(this, options)
}
util.inherits(EntryChangeNotificationControl, Control);
util.inherits(EntryChangeNotificationControl, Control)
Object.defineProperties(EntryChangeNotificationControl.prototype, {
value: {
get: function () { return this._value || {}; },
get: function () { return this._value || {} },
configurable: false
}
});
})
EntryChangeNotificationControl.prototype.parse = function parse(buffer) {
assert.ok(buffer);
EntryChangeNotificationControl.prototype.parse = function parse (buffer) {
assert.ok(buffer)
var ber = new BerReader(buffer);
var ber = new BerReader(buffer)
if (ber.readSequence()) {
this._value = {
changeType: ber.readInt()
};
}
// if the operation was moddn, then parse the optional previousDN attr
if (this._value.changeType === 8)
this._value.previousDN = ber.readString();
if (this._value.changeType === 8) { this._value.previousDN = ber.readString() }
this._value.changeNumber = ber.readInt();
this._value.changeNumber = ber.readInt()
return true;
return true
}
return false;
};
return false
}
EntryChangeNotificationControl.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
if (!this._value)
return;
if (!this._value) { return }
var writer = new BerWriter();
writer.startSequence();
writer.writeInt(this.value.changeType);
if (this.value.previousDN)
writer.writeString(this.value.previousDN);
var writer = new BerWriter()
writer.startSequence()
writer.writeInt(this.value.changeType)
if (this.value.previousDN) { writer.writeString(this.value.previousDN) }
writer.writeInt(parseInt(this.value.changeNumber, 10));
writer.endSequence();
writer.writeInt(parseInt(this.value.changeNumber, 10))
writer.endSequence()
ber.writeBuffer(writer.buffer, 0x04);
};
ber.writeBuffer(writer.buffer, 0x04)
}
EntryChangeNotificationControl.prototype._json = function (obj) {
obj.controlValue = this.value;
return obj;
};
obj.controlValue = this.value
return obj
}
EntryChangeNotificationControl.OID = '2.16.840.1.113730.3.4.7';
EntryChangeNotificationControl.OID = '2.16.840.1.113730.3.4.7'
///--- Exports
module.exports = EntryChangeNotificationControl;
/// --- Exports
module.exports = EntryChangeNotificationControl

View File

@ -1,73 +1,78 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var Ber = require('asn1').Ber;
var assert = require('assert')
var Ber = require('asn1').Ber
var Control = require('./control');
var Control = require('./control')
var EntryChangeNotificationControl =
require('./entry_change_notification_control');
var PersistentSearchControl = require('./persistent_search_control');
var PagedResultsControl = require('./paged_results_control');
require('./entry_change_notification_control')
var PersistentSearchControl = require('./persistent_search_control')
var PagedResultsControl = require('./paged_results_control')
var ServerSideSortingRequestControl =
require('./server_side_sorting_request_control.js');
require('./server_side_sorting_request_control.js')
var ServerSideSortingResponseControl =
require('./server_side_sorting_response_control.js');
require('./server_side_sorting_response_control.js')
var VirtualListViewRequestControl =
require('./virtual_list_view_request_control.js')
var VirtualListViewResponseControl =
require('./virtual_list_view_response_control.js')
///--- API
/// --- API
module.exports = {
getControl: function getControl(ber) {
assert.ok(ber);
getControl: function getControl (ber) {
assert.ok(ber)
if (ber.readSequence() === null)
return null;
if (ber.readSequence() === null) { return null }
var type;
var type
var opts = {
criticality: false,
value: null
};
}
if (ber.length) {
var end = ber.offset + ber.length;
var end = ber.offset + ber.length
type = ber.readString();
type = ber.readString()
if (ber.offset < end) {
if (ber.peek() === Ber.Boolean)
opts.criticality = ber.readBoolean();
if (ber.peek() === Ber.Boolean) { opts.criticality = ber.readBoolean() }
}
if (ber.offset < end)
opts.value = ber.readString(Ber.OctetString, true);
if (ber.offset < end) { opts.value = ber.readString(Ber.OctetString, true) }
}
var control;
var control
switch (type) {
case PersistentSearchControl.OID:
control = new PersistentSearchControl(opts);
break;
case EntryChangeNotificationControl.OID:
control = new EntryChangeNotificationControl(opts);
break;
case PagedResultsControl.OID:
control = new PagedResultsControl(opts);
break;
case ServerSideSortingRequestControl.OID:
control = new ServerSideSortingRequestControl(opts);
break;
case ServerSideSortingResponseControl.OID:
control = new ServerSideSortingResponseControl(opts);
break;
default:
opts.type = type;
control = new Control(opts);
break;
case PersistentSearchControl.OID:
control = new PersistentSearchControl(opts)
break
case EntryChangeNotificationControl.OID:
control = new EntryChangeNotificationControl(opts)
break
case PagedResultsControl.OID:
control = new PagedResultsControl(opts)
break
case ServerSideSortingRequestControl.OID:
control = new ServerSideSortingRequestControl(opts)
break
case ServerSideSortingResponseControl.OID:
control = new ServerSideSortingResponseControl(opts)
break
case VirtualListViewRequestControl.OID:
control = new VirtualListViewRequestControl(opts)
break
case VirtualListViewResponseControl.OID:
control = new VirtualListViewResponseControl(opts)
break
default:
opts.type = type
control = new Control(opts)
break
}
return control;
return control
},
Control: Control,
@ -75,5 +80,7 @@ module.exports = {
PagedResultsControl: PagedResultsControl,
PersistentSearchControl: PersistentSearchControl,
ServerSideSortingRequestControl: ServerSideSortingRequestControl,
ServerSideSortingResponseControl: ServerSideSortingResponseControl
};
ServerSideSortingResponseControl: ServerSideSortingResponseControl,
VirtualListViewRequestControl: VirtualListViewRequestControl,
VirtualListViewResponseControl: VirtualListViewResponseControl
}

View File

@ -1,87 +1,82 @@
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
var asn1 = require('asn1')
var Control = require('./control');
var Control = require('./control')
/// --- Globals
///--- Globals
var BerReader = asn1.BerReader
var BerWriter = asn1.BerWriter
var BerReader = asn1.BerReader;
var BerWriter = asn1.BerWriter;
/// --- API
///--- API
function PagedResultsControl(options) {
assert.optionalObject(options);
options = options || {};
options.type = PagedResultsControl.OID;
function PagedResultsControl (options) {
assert.optionalObject(options)
options = options || {}
options.type = PagedResultsControl.OID
if (options.value) {
if (Buffer.isBuffer(options.value)) {
this.parse(options.value);
this.parse(options.value)
} else if (typeof (options.value) === 'object') {
this._value = options.value;
this._value = options.value
} else {
throw new TypeError('options.value must be a Buffer or Object');
throw new TypeError('options.value must be a Buffer or Object')
}
options.value = null;
options.value = null
}
Control.call(this, options);
Control.call(this, options)
}
util.inherits(PagedResultsControl, Control);
util.inherits(PagedResultsControl, Control)
Object.defineProperties(PagedResultsControl.prototype, {
value: {
get: function () { return this._value || {}; },
get: function () { return this._value || {} },
configurable: false
}
});
})
PagedResultsControl.prototype.parse = function parse(buffer) {
assert.ok(buffer);
PagedResultsControl.prototype.parse = function parse (buffer) {
assert.ok(buffer)
var ber = new BerReader(buffer);
var ber = new BerReader(buffer)
if (ber.readSequence()) {
this._value = {};
this._value.size = ber.readInt();
this._value.cookie = ber.readString(asn1.Ber.OctetString, true);
//readString returns '' instead of a zero-length buffer
if (!this._value.cookie)
this._value.cookie = new Buffer(0);
this._value = {}
this._value.size = ber.readInt()
this._value.cookie = ber.readString(asn1.Ber.OctetString, true)
// readString returns '' instead of a zero-length buffer
if (!this._value.cookie) { this._value.cookie = Buffer.alloc(0) }
return true;
return true
}
return false;
};
return false
}
PagedResultsControl.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
if (!this._value)
return;
if (!this._value) { return }
var writer = new BerWriter();
writer.startSequence();
writer.writeInt(this.value.size);
var writer = new BerWriter()
writer.startSequence()
writer.writeInt(this.value.size)
if (this.value.cookie && this.value.cookie.length > 0) {
writer.writeBuffer(this.value.cookie, asn1.Ber.OctetString);
writer.writeBuffer(this.value.cookie, asn1.Ber.OctetString)
} else {
writer.writeString(''); //writeBuffer rejects zero-length buffers
writer.writeString('') // writeBuffer rejects zero-length buffers
}
writer.endSequence();
writer.endSequence()
ber.writeBuffer(writer.buffer, 0x04);
};
ber.writeBuffer(writer.buffer, 0x04)
}
PagedResultsControl.prototype._json = function (obj) {
obj.controlValue = this.value;
return obj;
};
obj.controlValue = this.value
return obj
}
PagedResultsControl.OID = '1.2.840.113556.1.4.319';
PagedResultsControl.OID = '1.2.840.113556.1.4.319'
///--- Exports
module.exports = PagedResultsControl;
/// --- Exports
module.exports = PagedResultsControl

View File

@ -1,85 +1,82 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
var asn1 = require('asn1')
var Control = require('./control');
var Control = require('./control')
/// --- Globals
///--- Globals
var BerReader = asn1.BerReader
var BerWriter = asn1.BerWriter
var BerReader = asn1.BerReader;
var BerWriter = asn1.BerWriter;
/// --- API
///--- API
function PersistentSearchControl(options) {
assert.optionalObject(options);
options = options || {};
options.type = PersistentSearchControl.OID;
function PersistentSearchControl (options) {
assert.optionalObject(options)
options = options || {}
options.type = PersistentSearchControl.OID
if (options.value) {
if (Buffer.isBuffer(options.value)) {
this.parse(options.value);
this.parse(options.value)
} else if (typeof (options.value) === 'object') {
this._value = options.value;
this._value = options.value
} else {
throw new TypeError('options.value must be a Buffer or Object');
throw new TypeError('options.value must be a Buffer or Object')
}
options.value = null;
options.value = null
}
Control.call(this, options);
Control.call(this, options)
}
util.inherits(PersistentSearchControl, Control);
util.inherits(PersistentSearchControl, Control)
Object.defineProperties(PersistentSearchControl.prototype, {
value: {
get: function () { return this._value || {}; },
get: function () { return this._value || {} },
configurable: false
}
});
})
PersistentSearchControl.prototype.parse = function parse(buffer) {
assert.ok(buffer);
PersistentSearchControl.prototype.parse = function parse (buffer) {
assert.ok(buffer)
var ber = new BerReader(buffer);
var ber = new BerReader(buffer)
if (ber.readSequence()) {
this._value = {
changeTypes: ber.readInt(),
changesOnly: ber.readBoolean(),
returnECs: ber.readBoolean()
};
}
return true;
return true
}
return false;
};
return false
}
PersistentSearchControl.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
if (!this._value)
return;
if (!this._value) { return }
var writer = new BerWriter();
writer.startSequence();
writer.writeInt(this.value.changeTypes);
writer.writeBoolean(this.value.changesOnly);
writer.writeBoolean(this.value.returnECs);
writer.endSequence();
var writer = new BerWriter()
writer.startSequence()
writer.writeInt(this.value.changeTypes)
writer.writeBoolean(this.value.changesOnly)
writer.writeBoolean(this.value.returnECs)
writer.endSequence()
ber.writeBuffer(writer.buffer, 0x04);
};
ber.writeBuffer(writer.buffer, 0x04)
}
PersistentSearchControl.prototype._json = function (obj) {
obj.controlValue = this.value;
return obj;
};
obj.controlValue = this.value
return obj
}
PersistentSearchControl.OID = '2.16.840.1.113730.3.4.3';
PersistentSearchControl.OID = '2.16.840.1.113730.3.4.3'
///--- Exports
module.exports = PersistentSearchControl;
/// --- Exports
module.exports = PersistentSearchControl

View File

@ -1,112 +1,108 @@
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
var asn1 = require('asn1')
var Control = require('./control');
var Control = require('./control')
/// --- Globals
///--- Globals
var BerReader = asn1.BerReader
var BerWriter = asn1.BerWriter
var BerReader = asn1.BerReader;
var BerWriter = asn1.BerWriter;
/// --- API
///--- API
function ServerSideSortingRequestControl(options) {
assert.optionalObject(options);
options = options || {};
options.type = ServerSideSortingRequestControl.OID;
function ServerSideSortingRequestControl (options) {
assert.optionalObject(options)
options = options || {}
options.type = ServerSideSortingRequestControl.OID
if (options.value) {
if (Buffer.isBuffer(options.value)) {
this.parse(options.value);
this.parse(options.value)
} else if (Array.isArray(options.value)) {
assert.arrayOfObject(options.value, 'options.value must be Objects');
assert.arrayOfObject(options.value, 'options.value must be Objects')
for (var i = 0; i < options.value.length; i++) {
if (!options.value[i].hasOwnProperty('attributeType')) {
throw new Error('Missing required key: attributeType');
if (Object.prototype.hasOwnProperty.call(options.value[i], 'attributeType') === false) {
throw new Error('Missing required key: attributeType')
}
}
this._value = options.value;
this._value = options.value
} else if (typeof (options.value) === 'object') {
if (!options.value.hasOwnProperty('attributeType')) {
throw new Error('Missing required key: attributeType');
if (Object.prototype.hasOwnProperty.call(options.value, 'attributeType') === false) {
throw new Error('Missing required key: attributeType')
}
this._value = [options.value];
this._value = [options.value]
} else {
throw new TypeError('options.value must be a Buffer, Array or Object');
throw new TypeError('options.value must be a Buffer, Array or Object')
}
options.value = null;
options.value = null
}
Control.call(this, options);
Control.call(this, options)
}
util.inherits(ServerSideSortingRequestControl, Control);
util.inherits(ServerSideSortingRequestControl, Control)
Object.defineProperties(ServerSideSortingRequestControl.prototype, {
value: {
get: function () { return this._value || []; },
get: function () { return this._value || [] },
configurable: false
}
});
})
ServerSideSortingRequestControl.prototype.parse = function parse(buffer) {
assert.ok(buffer);
ServerSideSortingRequestControl.prototype.parse = function parse (buffer) {
assert.ok(buffer)
var ber = new BerReader(buffer);
var item;
var ber = new BerReader(buffer)
var item
if (ber.readSequence(0x30)) {
this._value = [];
this._value = []
while (ber.readSequence(0x30)) {
item = {};
item.attributeType = ber.readString(asn1.Ber.OctetString);
if (ber.peek() == 0x80) {
item.orderingRule = ber.readString(0x80);
item = {}
item.attributeType = ber.readString(asn1.Ber.OctetString)
if (ber.peek() === 0x80) {
item.orderingRule = ber.readString(0x80)
}
if (ber.peek() == 0x81) {
item.reverseOrder = (ber._readTag(0x81) === 0 ? false : true);
if (ber.peek() === 0x81) {
item.reverseOrder = (ber._readTag(0x81) !== 0)
}
this._value.push(item);
this._value.push(item)
}
return true;
return true
}
return false;
};
return false
}
ServerSideSortingRequestControl.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
if (!this._value || this.value.length === 0)
return;
if (!this._value || this.value.length === 0) { return }
var writer = new BerWriter();
writer.startSequence(0x30);
var writer = new BerWriter()
writer.startSequence(0x30)
for (var i = 0; i < this.value.length; i++) {
var item = this.value[i];
writer.startSequence(0x30);
var item = this.value[i]
writer.startSequence(0x30)
if (item.attributeType) {
writer.writeString(item.attributeType, asn1.Ber.OctetString);
writer.writeString(item.attributeType, asn1.Ber.OctetString)
}
if (item.orderingRule) {
writer.writeString(item.orderingRule, 0x80);
writer.writeString(item.orderingRule, 0x80)
}
if (item.reverseOrder) {
writer.writeBoolean(item.reverseOrder, 0x81);
writer.writeBoolean(item.reverseOrder, 0x81)
}
writer.endSequence();
writer.endSequence()
}
writer.endSequence();
ber.writeBuffer(writer.buffer, 0x04);
};
writer.endSequence()
ber.writeBuffer(writer.buffer, 0x04)
}
ServerSideSortingRequestControl.prototype._json = function (obj) {
obj.controlValue = this.value;
return obj;
};
obj.controlValue = this.value
return obj
}
ServerSideSortingRequestControl.OID = '1.2.840.113556.1.4.473';
ServerSideSortingRequestControl.OID = '1.2.840.113556.1.4.473'
/// ---Exports
///---Exports
module.exports = ServerSideSortingRequestControl;
module.exports = ServerSideSortingRequestControl

View File

@ -1,16 +1,15 @@
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
var asn1 = require('asn1')
var Control = require('./control');
var CODES = require('../errors/codes');
var Control = require('./control')
var CODES = require('../errors/codes')
/// --- Globals
///--- Globals
var BerReader = asn1.BerReader;
var BerWriter = asn1.BerWriter;
var BerReader = asn1.BerReader
var BerWriter = asn1.BerWriter
var VALID_CODES = [
CODES.LDAP_SUCCESS,
@ -24,80 +23,78 @@ var VALID_CODES = [
CODES.LDAP_BUSY,
CODES.LDAP_UNWILLING_TO_PERFORM,
CODES.LDAP_OTHER
];
]
function ServerSideSortingResponseControl(options) {
assert.optionalObject(options);
options = options || {};
options.type = ServerSideSortingResponseControl.OID;
options.criticality = false;
function ServerSideSortingResponseControl (options) {
assert.optionalObject(options)
options = options || {}
options.type = ServerSideSortingResponseControl.OID
options.criticality = false
if (options.value) {
if (Buffer.isBuffer(options.value)) {
this.parse(options.value);
this.parse(options.value)
} else if (typeof (options.value) === 'object') {
if (VALID_CODES.indexOf(options.value.result) === -1) {
throw new Error('Invalid result code');
throw new Error('Invalid result code')
}
if (options.value.failedAttribute &&
typeof (options.value.failedAttribute) !== 'string') {
throw new Error('failedAttribute must be String');
throw new Error('failedAttribute must be String')
}
this._value = options.value;
this._value = options.value
} else {
throw new TypeError('options.value must be a Buffer or Object');
throw new TypeError('options.value must be a Buffer or Object')
}
options.value = null;
options.value = null
}
Control.call(this, options);
Control.call(this, options)
}
util.inherits(ServerSideSortingResponseControl, Control);
util.inherits(ServerSideSortingResponseControl, Control)
Object.defineProperties(ServerSideSortingResponseControl.prototype, {
value: {
get: function () { return this._value || {}; },
get: function () { return this._value || {} },
configurable: false
}
});
})
ServerSideSortingResponseControl.prototype.parse = function parse(buffer) {
assert.ok(buffer);
ServerSideSortingResponseControl.prototype.parse = function parse (buffer) {
assert.ok(buffer)
var ber = new BerReader(buffer);
var ber = new BerReader(buffer)
if (ber.readSequence(0x30)) {
this._value = {};
this._value.result = ber.readEnumeration();
if (ber.peek() == 0x80) {
this._value.failedAttribute = ber.readString(0x80);
this._value = {}
this._value.result = ber.readEnumeration()
if (ber.peek() === 0x80) {
this._value.failedAttribute = ber.readString(0x80)
}
return true;
return true
}
return false;
};
return false
}
ServerSideSortingResponseControl.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
if (!this._value || this.value.length === 0)
return;
if (!this._value || this.value.length === 0) { return }
var writer = new BerWriter();
writer.startSequence(0x30);
writer.writeEnumeration(this.value.result);
var writer = new BerWriter()
writer.startSequence(0x30)
writer.writeEnumeration(this.value.result)
if (this.value.result !== CODES.LDAP_SUCCESS && this.value.failedAttribute) {
writer.writeString(this.value.failedAttribute, 0x80);
writer.writeString(this.value.failedAttribute, 0x80)
}
writer.endSequence();
ber.writeBuffer(writer.buffer, 0x04);
};
writer.endSequence()
ber.writeBuffer(writer.buffer, 0x04)
}
ServerSideSortingResponseControl.prototype._json = function (obj) {
obj.controlValue = this.value;
return obj;
};
obj.controlValue = this.value
return obj
}
ServerSideSortingResponseControl.OID = '1.2.840.113556.1.4.474';
ServerSideSortingResponseControl.OID = '1.2.840.113556.1.4.474'
///--- Exports
module.exports = ServerSideSortingResponseControl;
/// --- Exports
module.exports = ServerSideSortingResponseControl

View File

@ -0,0 +1,94 @@
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1')
var Control = require('./control')
/// --- Globals
var BerReader = asn1.BerReader
var BerWriter = asn1.BerWriter
/// --- API
function VirtualListViewControl (options) {
assert.optionalObject(options)
options = options || {}
options.type = VirtualListViewControl.OID
if (options.value) {
if (Buffer.isBuffer(options.value)) {
this.parse(options.value)
} else if (typeof (options.value) === 'object') {
if (Object.prototype.hasOwnProperty.call(options.value, 'beforeCount') === false) {
throw new Error('Missing required key: beforeCount')
}
if (Object.prototype.hasOwnProperty.call(options.value, 'afterCount') === false) {
throw new Error('Missing required key: afterCount')
}
this._value = options.value
} else {
throw new TypeError('options.value must be a Buffer or Object')
}
options.value = null
}
Control.call(this, options)
}
util.inherits(VirtualListViewControl, Control)
Object.defineProperties(VirtualListViewControl.prototype, {
value: {
get: function () { return this._value || [] },
configurable: false
}
})
VirtualListViewControl.prototype.parse = function parse (buffer) {
assert.ok(buffer)
var ber = new BerReader(buffer)
if (ber.readSequence()) {
this._value = {}
this._value.beforeCount = ber.readInt()
this._value.afterCount = ber.readInt()
if (ber.peek() === 0xa0) {
if (ber.readSequence(0xa0)) {
this._value.targetOffset = ber.readInt()
this._value.contentCount = ber.readInt()
}
}
if (ber.peek() === 0x81) {
this._value.greaterThanOrEqual = ber.readString(0x81)
}
return true
}
return false
}
VirtualListViewControl.prototype._toBer = function (ber) {
assert.ok(ber)
if (!this._value || this.value.length === 0) {
return
}
var writer = new BerWriter()
writer.startSequence(0x30)
writer.writeInt(this.value.beforeCount)
writer.writeInt(this.value.afterCount)
if (this.value.targetOffset !== undefined) {
writer.startSequence(0xa0)
writer.writeInt(this.value.targetOffset)
writer.writeInt(this.value.contentCount)
writer.endSequence()
} else if (this.value.greaterThanOrEqual !== undefined) {
writer.writeString(this.value.greaterThanOrEqual, 0x81)
}
writer.endSequence()
ber.writeBuffer(writer.buffer, 0x04)
}
VirtualListViewControl.prototype._json = function (obj) {
obj.controlValue = this.value
return obj
}
VirtualListViewControl.OID = '2.16.840.1.113730.3.4.9'
/// ---Exports
module.exports = VirtualListViewControl

View File

@ -0,0 +1,112 @@
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1')
var Control = require('./control')
var CODES = require('../errors/codes')
/// --- Globals
var BerReader = asn1.BerReader
var BerWriter = asn1.BerWriter
var VALID_CODES = [
CODES.LDAP_SUCCESS,
CODES.LDAP_OPERATIONS_ERROR,
CODES.LDAP_UNWILLING_TO_PERFORM,
CODES.LDAP_INSUFFICIENT_ACCESS_RIGHTS,
CODES.LDAP_BUSY,
CODES.LDAP_TIME_LIMIT_EXCEEDED,
CODES.LDAP_ADMIN_LIMIT_EXCEEDED,
CODES.LDAP_SORT_CONTROL_MISSING,
CODES.LDAP_INDEX_RANGE_ERROR,
CODES.LDAP_CONTROL_ERROR,
CODES.LDAP_OTHER
]
function VirtualListViewResponseControl (options) {
assert.optionalObject(options)
options = options || {}
options.type = VirtualListViewResponseControl.OID
options.criticality = false
if (options.value) {
if (Buffer.isBuffer(options.value)) {
this.parse(options.value)
} else if (typeof (options.value) === 'object') {
if (VALID_CODES.indexOf(options.value.result) === -1) {
throw new Error('Invalid result code')
}
this._value = options.value
} else {
throw new TypeError('options.value must be a Buffer or Object')
}
options.value = null
}
Control.call(this, options)
}
util.inherits(VirtualListViewResponseControl, Control)
Object.defineProperties(VirtualListViewResponseControl.prototype, {
value: {
get: function () { return this._value || {} },
configurable: false
}
})
VirtualListViewResponseControl.prototype.parse = function parse (buffer) {
assert.ok(buffer)
var ber = new BerReader(buffer)
if (ber.readSequence()) {
this._value = {}
if (ber.peek(0x02)) {
this._value.targetPosition = ber.readInt()
}
if (ber.peek(0x02)) {
this._value.contentCount = ber.readInt()
}
this._value.result = ber.readEnumeration()
this._value.cookie = ber.readString(asn1.Ber.OctetString, true)
// readString returns '' instead of a zero-length buffer
if (!this._value.cookie) {
this._value.cookie = Buffer.alloc(0)
}
return true
}
return false
}
VirtualListViewResponseControl.prototype._toBer = function (ber) {
assert.ok(ber)
if (!this._value || this.value.length === 0) {
return
}
var writer = new BerWriter()
writer.startSequence()
if (this.value.targetPosition !== undefined) {
writer.writeInt(this.value.targetPosition)
}
if (this.value.contentCount !== undefined) {
writer.writeInt(this.value.contentCount)
}
writer.writeEnumeration(this.value.result)
if (this.value.cookie && this.value.cookie.length > 0) {
writer.writeBuffer(this.value.cookie, asn1.Ber.OctetString)
} else {
writer.writeString('') // writeBuffer rejects zero-length buffers
}
writer.endSequence()
ber.writeBuffer(writer.buffer, 0x04)
}
VirtualListViewResponseControl.prototype._json = function (obj) {
obj.controlValue = this.value
return obj
}
VirtualListViewResponseControl.OID = '2.16.840.1.113730.3.4.10'
/// --- Exports
module.exports = VirtualListViewResponseControl

50
lib/corked_emitter.js Normal file
View File

@ -0,0 +1,50 @@
'use strict'
var EventEmitter = require('events').EventEmitter
/**
* A CorkedEmitter is a variant of an EventEmitter where events emitted
* wait for the appearance of the first listener of any kind. That is,
* a CorkedEmitter will store all .emit()s it receives, to be replayed
* later when an .on() is applied.
* It is meant for situations where the consumers of the emitter are
* unable to register listeners right away, and cannot afford to miss
* any events emitted from the start.
* Note that, whenever the first emitter (for any event) appears,
* the emitter becomes uncorked and works as usual for ALL events, and
* will not cache anything anymore. This is necessary to avoid
* re-ordering emits - either everything is being buffered, or nothing.
*/
function CorkedEmitter () {
var self = this
EventEmitter.call(self)
/**
* An array of arguments objects (array-likes) to emit on open.
*/
self._outstandingEmits = []
/**
* Whether the normal flow of emits is restored yet.
*/
self._opened = false
// When the first listener appears, we enqueue an opening.
// It is not done immediately, so that other listeners can be
// registered in the same critical section.
self.once('newListener', function () {
setImmediate(function releaseStoredEvents () {
self._opened = true
self._outstandingEmits.forEach(function (args) {
self.emit.apply(self, args)
})
})
})
}
CorkedEmitter.prototype = Object.create(EventEmitter.prototype)
CorkedEmitter.prototype.emit = function emit (eventName) {
if (this._opened || eventName === 'newListener') {
EventEmitter.prototype.emit.apply(this, arguments)
} else {
this._outstandingEmits.push(arguments)
}
}
module.exports = CorkedEmitter

525
lib/dn.js
View File

@ -1,336 +1,317 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus')
var assert = require('assert-plus');
/// --- Helpers
///--- Helpers
function invalidDN(name) {
var e = new Error();
e.name = 'InvalidDistinguishedNameError';
e.message = name;
return e;
function invalidDN (name) {
var e = new Error()
e.name = 'InvalidDistinguishedNameError'
e.message = name
return e
}
function isAlphaNumeric(c) {
var re = /[A-Za-z0-9]/;
return re.test(c);
function isAlphaNumeric (c) {
var re = /[A-Za-z0-9]/
return re.test(c)
}
function isWhitespace(c) {
var re = /\s/;
return re.test(c);
function isWhitespace (c) {
var re = /\s/
return re.test(c)
}
function repeatChar(c, n) {
var out = '';
var max = n ? n : 0;
for (var i = 0; i < max; i++)
out += c;
return out;
function repeatChar (c, n) {
var out = ''
var max = n || 0
for (var i = 0; i < max; i++) { out += c }
return out
}
///--- API
/// --- API
function RDN(obj) {
var self = this;
this.attrs = {};
function RDN (obj) {
var self = this
this.attrs = {}
if (obj) {
Object.keys(obj).forEach(function (k) {
self.set(k, obj[k]);
});
self.set(k, obj[k])
})
}
}
RDN.prototype.set = function rdnSet(name, value, opts) {
assert.string(name, 'name (string) required');
assert.string(value, 'value (string) required');
RDN.prototype.set = function rdnSet (name, value, opts) {
assert.string(name, 'name (string) required')
assert.string(value, 'value (string) required')
var self = this;
var lname = name.toLowerCase();
var self = this
var lname = name.toLowerCase()
this.attrs[lname] = {
value: value,
name: name
};
}
if (opts && typeof (opts) === 'object') {
Object.keys(opts).forEach(function (k) {
if (k !== 'value')
self.attrs[lname][k] = opts[k];
});
if (k !== 'value') { self.attrs[lname][k] = opts[k] }
})
}
};
}
RDN.prototype.equals = function rdnEquals(rdn) {
if (typeof (rdn) !== 'object')
return false;
RDN.prototype.equals = function rdnEquals (rdn) {
if (typeof (rdn) !== 'object') { return false }
var ourKeys = Object.keys(this.attrs);
var theirKeys = Object.keys(rdn.attrs);
if (ourKeys.length !== theirKeys.length)
return false;
var ourKeys = Object.keys(this.attrs)
var theirKeys = Object.keys(rdn.attrs)
if (ourKeys.length !== theirKeys.length) { return false }
ourKeys.sort();
theirKeys.sort();
ourKeys.sort()
theirKeys.sort()
for (var i = 0; i < ourKeys.length; i++) {
if (ourKeys[i] !== theirKeys[i])
return false;
if (this.attrs[ourKeys[i]].value !== rdn.attrs[ourKeys[i]].value)
return false;
if (ourKeys[i] !== theirKeys[i]) { return false }
if (this.attrs[ourKeys[i]].value !== rdn.attrs[ourKeys[i]].value) { return false }
}
return true;
};
return true
}
/**
* Convert RDN to string according to specified formatting options.
* (see: DN.format for option details)
*/
RDN.prototype.format = function rdnFormat(options) {
assert.optionalObject(options, 'options must be an object');
options = options || {};
RDN.prototype.format = function rdnFormat (options) {
assert.optionalObject(options, 'options must be an object')
options = options || {}
var self = this;
var str = '';
var self = this
var str = ''
function escapeValue(val, forceQuote) {
var out = '';
var cur = 0;
var len = val.length;
var quoted = false;
function escapeValue (val, forceQuote) {
var out = ''
var cur = 0
var len = val.length
var quoted = false
/* BEGIN JSSTYLED */
var escaped = /[\\\"]/;
var special = /[,=+<>#;]/;
// TODO: figure out what this regex is actually trying to test for and
// fix it to appease the linter.
/* eslint-disable-next-line no-useless-escape */
var escaped = /[\\\"]/
var special = /[,=+<>#;]/
/* END JSSTYLED */
if (len > 0) {
// Wrap strings with trailing or leading spaces in quotes
quoted = forceQuote || (val[0] == ' ' || val[len-1] == ' ');
quoted = forceQuote || (val[0] === ' ' || val[len - 1] === ' ')
}
while (cur < len) {
if (escaped.test(val[cur]) || (!quoted && special.test(val[cur]))) {
out += '\\';
out += '\\'
}
out += val[cur++];
out += val[cur++]
}
if (quoted)
out = '"' + out + '"';
return out;
if (quoted) { out = '"' + out + '"' }
return out
}
function sortParsed(a, b) {
return self.attrs[a].order - self.attrs[b].order;
function sortParsed (a, b) {
return self.attrs[a].order - self.attrs[b].order
}
function sortStandard(a, b) {
var nameCompare = a.localeCompare(b);
function sortStandard (a, b) {
var nameCompare = a.localeCompare(b)
if (nameCompare === 0) {
// TODO: Handle binary values
return self.attrs[a].value.localeCompare(self.attrs[b].value);
return self.attrs[a].value.localeCompare(self.attrs[b].value)
} else {
return nameCompare;
return nameCompare
}
}
var keys = Object.keys(this.attrs);
var keys = Object.keys(this.attrs)
if (options.keepOrder) {
keys.sort(sortParsed);
keys.sort(sortParsed)
} else {
keys.sort(sortStandard);
keys.sort(sortStandard)
}
keys.forEach(function (key) {
var attr = self.attrs[key];
if (str.length)
str += '+';
var attr = self.attrs[key]
if (str.length) { str += '+' }
if (options.keepCase) {
str += attr.name;
str += attr.name
} else {
if (options.upperName)
str += key.toUpperCase();
else
str += key;
if (options.upperName) { str += key.toUpperCase() } else { str += key }
}
str += '=' + escapeValue(attr.value, (options.keepQuote && attr.quoted));
});
str += '=' + escapeValue(attr.value, (options.keepQuote && attr.quoted))
})
return str;
};
RDN.prototype.toString = function rdnToString() {
return this.format();
};
return str
}
RDN.prototype.toString = function rdnToString () {
return this.format()
}
// Thank you OpenJDK!
function parse(name) {
if (typeof (name) !== 'string')
throw new TypeError('name (string) required');
function parse (name) {
if (typeof (name) !== 'string') { throw new TypeError('name (string) required') }
var cur = 0;
var len = name.length;
var cur = 0
var len = name.length
function parseRdn() {
var rdn = new RDN();
var order = 0;
rdn.spLead = trim();
function parseRdn () {
var rdn = new RDN()
var order = 0
rdn.spLead = trim()
while (cur < len) {
var opts = {
order: order
};
var attr = parseAttrType();
trim();
if (cur >= len || name[cur++] !== '=')
throw invalidDN(name);
}
var attr = parseAttrType()
trim()
if (cur >= len || name[cur++] !== '=') { throw invalidDN(name) }
trim();
trim()
// Parameters about RDN value are set in 'opts' by parseAttrValue
var value = parseAttrValue(opts);
rdn.set(attr, value, opts);
rdn.spTrail = trim();
if (cur >= len || name[cur] !== '+')
break;
++cur;
++order;
var value = parseAttrValue(opts)
rdn.set(attr, value, opts)
rdn.spTrail = trim()
if (cur >= len || name[cur] !== '+') { break }
++cur
++order
}
return rdn;
return rdn
}
function trim() {
var count = 0;
function trim () {
var count = 0
while ((cur < len) && isWhitespace(name[cur])) {
++cur;
count++;
++cur
count++
}
return count;
return count
}
function parseAttrType() {
var beg = cur;
function parseAttrType () {
var beg = cur
while (cur < len) {
var c = name[cur];
var c = name[cur]
if (isAlphaNumeric(c) ||
c == '.' ||
c == '-' ||
c == ' ') {
++cur;
c === '.' ||
c === '-' ||
c === ' ') {
++cur
} else {
break;
break
}
}
// Back out any trailing spaces.
while ((cur > beg) && (name[cur - 1] == ' '))
--cur;
while ((cur > beg) && (name[cur - 1] === ' ')) { --cur }
if (beg == cur)
throw invalidDN(name);
if (beg === cur) { throw invalidDN(name) }
return name.slice(beg, cur);
return name.slice(beg, cur)
}
function parseAttrValue(opts) {
if (cur < len && name[cur] == '#') {
opts.binary = true;
return parseBinaryAttrValue();
} else if (cur < len && name[cur] == '"') {
opts.quoted = true;
return parseQuotedAttrValue();
function parseAttrValue (opts) {
if (cur < len && name[cur] === '#') {
opts.binary = true
return parseBinaryAttrValue()
} else if (cur < len && name[cur] === '"') {
opts.quoted = true
return parseQuotedAttrValue()
} else {
return parseStringAttrValue();
return parseStringAttrValue()
}
}
function parseBinaryAttrValue() {
var beg = cur++;
while (cur < len && isAlphaNumeric(name[cur]))
++cur;
function parseBinaryAttrValue () {
var beg = cur++
while (cur < len && isAlphaNumeric(name[cur])) { ++cur }
return name.slice(beg, cur);
return name.slice(beg, cur)
}
function parseQuotedAttrValue() {
var str = '';
++cur; // Consume the first quote
function parseQuotedAttrValue () {
var str = ''
++cur // Consume the first quote
while ((cur < len) && name[cur] != '"') {
if (name[cur] === '\\')
cur++;
str += name[cur++];
while ((cur < len) && name[cur] !== '"') {
if (name[cur] === '\\') { cur++ }
str += name[cur++]
}
if (cur++ >= len) {
// no closing quote
throw invalidDN(name)
}
if (cur++ >= len) // no closing quote
throw invalidDN(name);
return str;
return str
}
function parseStringAttrValue() {
var beg = cur;
var str = '';
var esc = -1;
function parseStringAttrValue () {
var beg = cur
var str = ''
var esc = -1
while ((cur < len) && !atTerminator()) {
if (name[cur] === '\\') {
// Consume the backslash and mark its place just in case it's escaping
// whitespace which needs to be preserved.
esc = cur++;
esc = cur++
}
if (cur === len) // backslash followed by nothing
throw invalidDN(name);
str += name[cur++];
if (cur === len) {
// backslash followed by nothing
throw invalidDN(name)
}
str += name[cur++]
}
// Trim off (unescaped) trailing whitespace and rewind cursor to the end of
// the AttrValue to record whitespace length.
for (; cur > beg; cur--) {
if (!isWhitespace(name[cur - 1]) || (esc === (cur - 1)))
break;
if (!isWhitespace(name[cur - 1]) || (esc === (cur - 1))) { break }
}
return str.slice(0, cur - beg);
return str.slice(0, cur - beg)
}
function atTerminator() {
function atTerminator () {
return (cur < len &&
(name[cur] === ',' ||
name[cur] === ';' ||
name[cur] === '+'));
name[cur] === '+'))
}
var rdns = [];
var rdns = []
// Short-circuit for empty DNs
if (len === 0)
return new DN(rdns);
if (len === 0) { return new DN(rdns) }
rdns.push(parseRdn());
rdns.push(parseRdn())
while (cur < len) {
if (name[cur] === ',' || name[cur] === ';') {
++cur;
rdns.push(parseRdn());
++cur
rdns.push(parseRdn())
} else {
throw invalidDN(name);
throw invalidDN(name)
}
}
return new DN(rdns);
return new DN(rdns)
}
function DN (rdns) {
assert.optionalArrayOfObject(rdns, '[object] required')
function DN(rdns) {
assert.optionalArrayOfObject(rdns, '[object] required');
this.rdns = rdns ? rdns.slice() : [];
this._format = {};
this.rdns = rdns ? rdns.slice() : []
this._format = {}
}
Object.defineProperties(DN.prototype, {
length: {
get: function getLength() { return this.rdns.length; },
get: function getLength () { return this.rdns.length },
configurable: false
}
});
})
/**
* Convert DN to string according to specified formatting options.
@ -355,146 +336,138 @@ Object.defineProperties(DN.prototype, {
* - upperName: RDN names will be uppercased instead of lowercased.
* - skipSpace: Disable trailing space after RDN separators
*/
DN.prototype.format = function dnFormat(options) {
assert.optionalObject(options, 'options must be an object');
options = options || this._format;
DN.prototype.format = function dnFormat (options) {
assert.optionalObject(options, 'options must be an object')
options = options || this._format
var str = '';
var str = ''
this.rdns.forEach(function (rdn) {
var rdnString = rdn.format(options);
var rdnString = rdn.format(options)
if (str.length !== 0) {
str += ',';
str += ','
}
if (options.keepSpace) {
str += (repeatChar(' ', rdn.spLead) +
rdnString + repeatChar(' ', rdn.spTrail));
rdnString + repeatChar(' ', rdn.spTrail))
} else if (options.skipSpace === true || str.length === 0) {
str += rdnString;
str += rdnString
} else {
str += ' ' + rdnString;
str += ' ' + rdnString
}
});
return str;
};
})
return str
}
/**
* Set default string formatting options.
*/
DN.prototype.setFormat = function setFormat(options) {
assert.object(options, 'options must be an object');
DN.prototype.setFormat = function setFormat (options) {
assert.object(options, 'options must be an object')
this._format = options;
};
this._format = options
}
DN.prototype.toString = function dnToString() {
return this.format();
};
DN.prototype.toString = function dnToString () {
return this.format()
}
DN.prototype.parentOf = function parentOf(dn) {
if (typeof (dn) !== 'object')
dn = parse(dn);
DN.prototype.parentOf = function parentOf (dn) {
if (typeof (dn) !== 'object') { dn = parse(dn) }
if (this.rdns.length >= dn.rdns.length)
return false;
if (this.rdns.length >= dn.rdns.length) { return false }
var diff = dn.rdns.length - this.rdns.length;
var diff = dn.rdns.length - this.rdns.length
for (var i = this.rdns.length - 1; i >= 0; i--) {
var myRDN = this.rdns[i];
var theirRDN = dn.rdns[i + diff];
var myRDN = this.rdns[i]
var theirRDN = dn.rdns[i + diff]
if (!myRDN.equals(theirRDN))
return false;
if (!myRDN.equals(theirRDN)) { return false }
}
return true;
};
return true
}
DN.prototype.childOf = function childOf(dn) {
if (typeof (dn) !== 'object')
dn = parse(dn);
return dn.parentOf(this);
};
DN.prototype.childOf = function childOf (dn) {
if (typeof (dn) !== 'object') { dn = parse(dn) }
return dn.parentOf(this)
}
DN.prototype.isEmpty = function isEmpty() {
return (this.rdns.length === 0);
};
DN.prototype.isEmpty = function isEmpty () {
return (this.rdns.length === 0)
}
DN.prototype.equals = function dnEquals(dn) {
if (typeof (dn) !== 'object')
dn = parse(dn);
DN.prototype.equals = function dnEquals (dn) {
if (typeof (dn) !== 'object') { dn = parse(dn) }
if (this.rdns.length !== dn.rdns.length)
return false;
if (this.rdns.length !== dn.rdns.length) { return false }
for (var i = 0; i < this.rdns.length; i++) {
if (!this.rdns[i].equals(dn.rdns[i]))
return false;
if (!this.rdns[i].equals(dn.rdns[i])) { return false }
}
return true;
};
return true
}
DN.prototype.parent = function dnParent() {
DN.prototype.parent = function dnParent () {
if (this.rdns.length !== 0) {
var save = this.rdns.shift();
var dn = new DN(this.rdns);
this.rdns.unshift(save);
return dn;
var save = this.rdns.shift()
var dn = new DN(this.rdns)
this.rdns.unshift(save)
return dn
}
return null;
};
return null
}
DN.prototype.clone = function dnClone() {
var dn = new DN(this.rdns);
dn._format = this._format;
return dn;
};
DN.prototype.clone = function dnClone () {
var dn = new DN(this.rdns)
dn._format = this._format
return dn
}
DN.prototype.reverse = function dnReverse() {
this.rdns.reverse();
return this;
};
DN.prototype.reverse = function dnReverse () {
this.rdns.reverse()
return this
}
DN.prototype.pop = function dnPop() {
return this.rdns.pop();
};
DN.prototype.pop = function dnPop () {
return this.rdns.pop()
}
DN.prototype.push = function dnPush(rdn) {
assert.object(rdn, 'rdn (RDN) required');
DN.prototype.push = function dnPush (rdn) {
assert.object(rdn, 'rdn (RDN) required')
return this.rdns.push(rdn);
};
return this.rdns.push(rdn)
}
DN.prototype.shift = function dnShift() {
return this.rdns.shift();
};
DN.prototype.shift = function dnShift () {
return this.rdns.shift()
}
DN.prototype.unshift = function dnUnshift(rdn) {
assert.object(rdn, 'rdn (RDN) required');
DN.prototype.unshift = function dnUnshift (rdn) {
assert.object(rdn, 'rdn (RDN) required')
return this.rdns.unshift(rdn);
};
return this.rdns.unshift(rdn)
}
DN.isDN = function isDN(dn) {
DN.isDN = function isDN (dn) {
if (!dn || typeof (dn) !== 'object') {
return false;
return false
}
if (dn instanceof DN) {
return true;
return true
}
if (Array.isArray(dn.rdns)) {
// Really simple duck-typing for now
return true;
return true
}
return false;
};
return false
}
///--- Exports
/// --- Exports
module.exports = {
parse: parse,
DN: DN,
RDN: RDN
};
}

View File

@ -1,12 +1,10 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.s
/// --- Globals
///--- Globals
var SERVER_PROVIDER;
var DTRACE_ID = 0;
var MAX_INT = 4294967295;
var SERVER_PROVIDER
var DTRACE_ID = 0
var MAX_INT = 4294967295
/*
* Args:
@ -37,7 +35,7 @@ var SERVER_PROBES = {
// 4: attribute, 5: value
'server-compare-start': ['int', 'char *', 'char *', 'char *',
'char *', 'char *'],
'char *', 'char *'],
'server-compare-done': ['int', 'char *', 'char *', 'char *', 'int', 'char *'],
'server-delete-start': ['int', 'char *', 'char *', 'char *'],
@ -45,7 +43,7 @@ var SERVER_PROBES = {
// 4: requestName, 5: requestValue
'server-exop-start': ['int', 'char *', 'char *', 'char *', 'char *',
'char *'],
'char *'],
'server-exop-done': ['int', 'char *', 'char *', 'char *', 'int', 'char *'],
// 4: changes.length
@ -54,13 +52,13 @@ var SERVER_PROBES = {
// 4: newRdn, 5: newSuperior
'server-modifydn-start': ['int', 'char *', 'char *', 'char *', 'char *',
'char *'],
'char *'],
'server-modifydn-done': ['int', 'char *', 'char *', 'char *', 'int',
'char *'],
'char *'],
// 4: scope, 5: filter
'server-search-start': ['int', 'char *', 'char *', 'char *', 'char *',
'char *'],
'char *'],
'server-search-done': ['int', 'char *', 'char *', 'char *', 'int', 'char *'],
// Last two are searchEntry.DN and seachEntry.attributes.length
'server-search-entry': ['int', 'char *', 'char *', 'char *', 'char *', 'int'],
@ -73,52 +71,50 @@ var SERVER_PROBES = {
// remote IP
'server-connection': ['char *']
};
}
/// --- API
///--- API
module.exports = function () {
module.exports = (function () {
if (!SERVER_PROVIDER) {
try {
var dtrace = require('dtrace-provider');
SERVER_PROVIDER = dtrace.createDTraceProvider('ldapjs');
var dtrace = require('dtrace-provider')
SERVER_PROVIDER = dtrace.createDTraceProvider('ldapjs')
Object.keys(SERVER_PROBES).forEach(function (p) {
var args = SERVER_PROBES[p].splice(0);
args.unshift(p);
var args = SERVER_PROBES[p].splice(0)
args.unshift(p)
dtrace.DTraceProvider.prototype.addProbe.apply(SERVER_PROVIDER, args);
});
dtrace.DTraceProvider.prototype.addProbe.apply(SERVER_PROVIDER, args)
})
} catch (e) {
SERVER_PROVIDER = {
fire: function () {
},
enable: function () {
},
addProbe: function () {
var p = {
fire: function () {
}
};
return (p);
},
removeProbe: function () {
},
disable: function () {
fire: function () {
},
enable: function () {
},
addProbe: function () {
var p = {
fire: function () {
}
}
};
return (p)
},
removeProbe: function () {
},
disable: function () {
}
}
}
SERVER_PROVIDER.enable();
SERVER_PROVIDER.enable()
SERVER_PROVIDER._nextId = function () {
if (DTRACE_ID === MAX_INT)
DTRACE_ID = 0;
if (DTRACE_ID === MAX_INT) { DTRACE_ID = 0 }
return ++DTRACE_ID;
};
return ++DTRACE_ID
}
}
return SERVER_PROVIDER;
}();
return SERVER_PROVIDER
}())

View File

@ -1,4 +1,4 @@
// Copyright 2014 Joyent, Inc. All rights reserved.
'use strict'
module.exports = {
LDAP_SUCCESS: 0,
@ -32,6 +32,8 @@ module.exports = {
LDAP_UNAVAILABLE: 52,
LDAP_UNWILLING_TO_PERFORM: 53,
LDAP_LOOP_DETECT: 54,
LDAP_SORT_CONTROL_MISSING: 60,
LDAP_INDEX_RANGE_ERROR: 61,
LDAP_NAMING_VIOLATION: 64,
LDAP_OBJECTCLASS_VIOLATION: 65,
LDAP_NOT_ALLOWED_ON_NON_LEAF: 66,
@ -39,6 +41,7 @@ module.exports = {
LDAP_ENTRY_ALREADY_EXISTS: 68,
LDAP_OBJECTCLASS_MODS_PROHIBITED: 69,
LDAP_AFFECTS_MULTIPLE_DSAS: 71,
LDAP_CONTROL_ERROR: 76,
LDAP_OTHER: 80,
LDAP_PROXIED_AUTHORIZATION_DENIED: 123
};
}

View File

@ -1,151 +1,144 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
'use strict'
var util = require('util');
var assert = require('assert-plus');
var util = require('util')
var assert = require('assert-plus')
var LDAPResult = require('../messages').LDAPResult;
var LDAPResult = require('../messages').LDAPResult
/// --- Globals
///--- Globals
var CODES = require('./codes')
var ERRORS = []
var CODES = require('./codes');
var ERRORS = [];
/// --- Error Base class
function LDAPError (message, dn, caller) {
if (Error.captureStackTrace) { Error.captureStackTrace(this, caller || LDAPError) }
///--- Error Base class
function LDAPError(message, dn, caller) {
if (Error.captureStackTrace)
Error.captureStackTrace(this, caller || LDAPError);
this.lde_message = message;
this.lde_dn = dn;
this.lde_message = message
this.lde_dn = dn
}
util.inherits(LDAPError, Error);
util.inherits(LDAPError, Error)
Object.defineProperties(LDAPError.prototype, {
name: {
get: function getName() { return 'LDAPError'; },
get: function getName () { return 'LDAPError' },
configurable: false
},
code: {
get: function getCode() { return CODES.LDAP_OTHER; },
get: function getCode () { return CODES.LDAP_OTHER },
configurable: false
},
message: {
get: function getMessage() {
return this.lde_message || this.name;
get: function getMessage () {
return this.lde_message || this.name
},
configurable: false
},
dn: {
get: function getDN() {
return (this.lde_dn ? this.lde_dn.toString() : '');
get: function getDN () {
return (this.lde_dn ? this.lde_dn.toString() : '')
},
configurable: false
}
});
})
/// --- Exported API
///--- Exported API
module.exports = {};
module.exports.LDAPError = LDAPError;
module.exports = {}
module.exports.LDAPError = LDAPError
// Some whacky games here to make sure all the codes are exported
Object.keys(CODES).forEach(function (code) {
module.exports[code] = CODES[code];
if (code === 'LDAP_SUCCESS')
return;
module.exports[code] = CODES[code]
if (code === 'LDAP_SUCCESS') { return }
var err = '';
var msg = '';
var pieces = code.split('_').slice(1);
var err = ''
var msg = ''
var pieces = code.split('_').slice(1)
for (var i = 0; i < pieces.length; i++) {
var lc = pieces[i].toLowerCase();
var key = lc.charAt(0).toUpperCase() + lc.slice(1);
err += key;
msg += key + ((i + 1) < pieces.length ? ' ' : '');
var lc = pieces[i].toLowerCase()
var key = lc.charAt(0).toUpperCase() + lc.slice(1)
err += key
msg += key + ((i + 1) < pieces.length ? ' ' : '')
}
if (!/\w+Error$/.test(err))
err += 'Error';
if (!/\w+Error$/.test(err)) { err += 'Error' }
// At this point LDAP_OPERATIONS_ERROR is now OperationsError in $err
// and 'Operations Error' in $msg
module.exports[err] = function (message, dn, caller) {
LDAPError.call(this, message, dn, caller || module.exports[err]);
};
module.exports[err].constructor = module.exports[err];
util.inherits(module.exports[err], LDAPError);
LDAPError.call(this, message, dn, caller || module.exports[err])
}
module.exports[err].constructor = module.exports[err]
util.inherits(module.exports[err], LDAPError)
Object.defineProperties(module.exports[err].prototype, {
name: {
get: function getName() { return err; },
get: function getName () { return err },
configurable: false
},
code: {
get: function getCode() { return CODES[code]; },
get: function getCode () { return CODES[code] },
configurable: false
}
});
})
ERRORS[CODES[code]] = {
err: err,
message: msg
};
});
}
})
module.exports.getError = function (res) {
assert.ok(res instanceof LDAPResult, 'res (LDAPResult) required');
assert.ok(res instanceof LDAPResult, 'res (LDAPResult) required')
var errObj = ERRORS[res.status];
var E = module.exports[errObj.err];
var errObj = ERRORS[res.status]
var E = module.exports[errObj.err]
return new E(res.errorMessage || errObj.message,
res.matchedDN || null,
module.exports.getError);
};
res.matchedDN || null,
module.exports.getError)
}
module.exports.getMessage = function (code) {
assert.number(code, 'code (number) required');
assert.number(code, 'code (number) required')
var errObj = ERRORS[code];
return (errObj && errObj.message ? errObj.message : '');
};
///--- Custom application errors
function ConnectionError(message) {
LDAPError.call(this, message, null, ConnectionError);
var errObj = ERRORS[code]
return (errObj && errObj.message ? errObj.message : '')
}
util.inherits(ConnectionError, LDAPError);
module.exports.ConnectionError = ConnectionError;
/// --- Custom application errors
function ConnectionError (message) {
LDAPError.call(this, message, null, ConnectionError)
}
util.inherits(ConnectionError, LDAPError)
module.exports.ConnectionError = ConnectionError
Object.defineProperties(ConnectionError.prototype, {
name: {
get: function () { return 'ConnectionError'; },
get: function () { return 'ConnectionError' },
configurable: false
}
});
})
function AbandonedError(message) {
LDAPError.call(this, message, null, AbandonedError);
function AbandonedError (message) {
LDAPError.call(this, message, null, AbandonedError)
}
util.inherits(AbandonedError, LDAPError);
module.exports.AbandonedError = AbandonedError;
util.inherits(AbandonedError, LDAPError)
module.exports.AbandonedError = AbandonedError
Object.defineProperties(AbandonedError.prototype, {
name: {
get: function () { return 'AbandonedError'; },
get: function () { return 'AbandonedError' },
configurable: false
}
});
})
function TimeoutError(message) {
LDAPError.call(this, message, null, TimeoutError);
function TimeoutError (message) {
LDAPError.call(this, message, null, TimeoutError)
}
util.inherits(TimeoutError, LDAPError);
module.exports.TimeoutError = TimeoutError;
util.inherits(TimeoutError, LDAPError)
module.exports.TimeoutError = TimeoutError
Object.defineProperties(TimeoutError.prototype, {
name: {
get: function () { return 'TimeoutError'; },
get: function () { return 'TimeoutError' },
configurable: false
}
});
})

View File

@ -1,30 +1,27 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var util = require('util');
var assert = require('assert')
var util = require('util')
var parents = require('ldap-filter');
var parents = require('ldap-filter')
var Filter = require('./filter');
var Filter = require('./filter')
/// --- API
///--- API
function AndFilter(options) {
parents.AndFilter.call(this, options);
function AndFilter (options) {
parents.AndFilter.call(this, options)
}
util.inherits(AndFilter, parents.AndFilter);
Filter.mixin(AndFilter);
module.exports = AndFilter;
util.inherits(AndFilter, parents.AndFilter)
Filter.mixin(AndFilter)
module.exports = AndFilter
AndFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.filters.forEach(function (f) {
ber = f.toBer(ber);
});
ber = f.toBer(ber)
})
return ber;
};
return ber
}

View File

@ -1,39 +1,35 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var util = require('util');
var assert = require('assert')
var util = require('util')
var parents = require('ldap-filter');
var parents = require('ldap-filter')
var Filter = require('./filter');
var Filter = require('./filter')
/// --- API
///--- API
function ApproximateFilter(options) {
parents.ApproximateFilter.call(this, options);
function ApproximateFilter (options) {
parents.ApproximateFilter.call(this, options)
}
util.inherits(ApproximateFilter, parents.ApproximateFilter);
Filter.mixin(ApproximateFilter);
module.exports = ApproximateFilter;
util.inherits(ApproximateFilter, parents.ApproximateFilter)
Filter.mixin(ApproximateFilter)
module.exports = ApproximateFilter
ApproximateFilter.prototype.parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.attribute = ber.readString().toLowerCase();
this.value = ber.readString();
return true;
};
this.attribute = ber.readString().toLowerCase()
this.value = ber.readString()
return true
}
ApproximateFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.attribute);
ber.writeString(this.value);
ber.writeString(this.attribute)
ber.writeString(this.value)
return ber;
};
return ber
}

View File

@ -1,66 +1,60 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var ASN1 = require('asn1').Ber;
var parents = require('ldap-filter');
var ASN1 = require('asn1').Ber
var parents = require('ldap-filter')
var Filter = require('./filter');
var Filter = require('./filter')
/// --- API
///--- API
function EqualityFilter(options) {
parents.EqualityFilter.call(this, options);
function EqualityFilter (options) {
parents.EqualityFilter.call(this, options)
}
util.inherits(EqualityFilter, parents.EqualityFilter);
Filter.mixin(EqualityFilter);
module.exports = EqualityFilter;
util.inherits(EqualityFilter, parents.EqualityFilter)
Filter.mixin(EqualityFilter)
module.exports = EqualityFilter
EqualityFilter.prototype.matches = function (target, strictAttrCase) {
assert.object(target, 'target');
assert.object(target, 'target')
var tv = parents.getAttrValue(target, this.attribute, strictAttrCase);
var value = this.value;
var tv = parents.getAttrValue(target, this.attribute, strictAttrCase)
var value = this.value
if (this.attribute.toLowerCase() === 'objectclass') {
/*
* Perform case-insensitive match for objectClass since nearly every LDAP
* implementation behaves in this manner.
*/
value = value.toLowerCase();
value = value.toLowerCase()
return parents.testValues(function (v) {
return value === v.toLowerCase();
}, tv);
return value === v.toLowerCase()
}, tv)
} else {
return parents.testValues(function (v) {
return value === v;
}, tv);
return value === v
}, tv)
}
};
}
EqualityFilter.prototype.parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.attribute = ber.readString().toLowerCase();
this.value = ber.readString(ASN1.OctetString, true);
this.attribute = ber.readString().toLowerCase()
this.value = ber.readString(ASN1.OctetString, true)
if (this.attribute === 'objectclass')
this.value = this.value.toLowerCase();
return true;
};
if (this.attribute === 'objectclass') { this.value = this.value.toLowerCase() }
return true
}
EqualityFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.attribute);
ber.writeBuffer(this.raw, ASN1.OctetString);
ber.writeString(this.attribute)
ber.writeBuffer(this.raw, ASN1.OctetString)
return ber;
};
return ber
}

View File

@ -14,32 +14,31 @@
*/
exports.escape = function (inp) {
if (typeof (inp) === 'string') {
var esc = '';
var esc = ''
for (var i = 0; i < inp.length; i++) {
switch (inp[i]) {
case '*':
esc += '\\2a';
break;
esc += '\\2a'
break
case '(':
esc += '\\28';
break;
esc += '\\28'
break
case ')':
esc += '\\29';
break;
esc += '\\29'
break
case '\\':
esc += '\\5c';
break;
esc += '\\5c'
break
case '\0':
esc += '\\00';
break;
esc += '\\00'
break
default:
esc += inp[i];
break;
esc += inp[i]
break
}
}
return esc;
return esc
} else {
return inp;
return inp
}
};
}

View File

@ -1,66 +1,59 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var util = require('util');
var parents = require('ldap-filter');
var Filter = require('./filter');
var assert = require('assert')
var util = require('util')
var parents = require('ldap-filter')
var Filter = require('./filter')
// THIS IS A STUB!
//
// ldapjs does not support server side extensible matching.
// This class exists only for the client to send them.
///--- API
/// --- API
function ExtensibleFilter(options) {
parents.ExtensibleFilter.call(this, options);
function ExtensibleFilter (options) {
parents.ExtensibleFilter.call(this, options)
}
util.inherits(ExtensibleFilter, parents.ExtensibleFilter);
Filter.mixin(ExtensibleFilter);
module.exports = ExtensibleFilter;
util.inherits(ExtensibleFilter, parents.ExtensibleFilter)
Filter.mixin(ExtensibleFilter)
module.exports = ExtensibleFilter
ExtensibleFilter.prototype.parse = function (ber) {
var end = ber.offset + ber.length;
var end = ber.offset + ber.length
while (ber.offset < end) {
var tag = ber.peek();
var tag = ber.peek()
switch (tag) {
case 0x81:
this.rule = ber.readString(tag);
break;
case 0x82:
this.matchType = ber.readString(tag);
break;
case 0x83:
this.value = ber.readString(tag);
break;
case 0x84:
this.dnAttributes = ber.readBoolean(tag);
break;
default:
throw new Error('Invalid ext_match filter type: 0x' + tag.toString(16));
case 0x81:
this.rule = ber.readString(tag)
break
case 0x82:
this.matchType = ber.readString(tag)
break
case 0x83:
this.value = ber.readString(tag)
break
case 0x84:
this.dnAttributes = ber.readBoolean(tag)
break
default:
throw new Error('Invalid ext_match filter type: 0x' + tag.toString(16))
}
}
return true;
};
return true
}
ExtensibleFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
if (this.rule)
ber.writeString(this.rule, 0x81);
if (this.matchType)
ber.writeString(this.matchType, 0x82);
if (this.rule) { ber.writeString(this.rule, 0x81) }
if (this.matchType) { ber.writeString(this.matchType, 0x82) }
ber.writeString(this.value, 0x83);
if (this.dnAttributes)
ber.writeBoolean(this.dnAttributes, 0x84);
ber.writeString(this.value, 0x83)
if (this.dnAttributes) { ber.writeBoolean(this.dnAttributes, 0x84) }
return ber;
};
return ber
}

View File

@ -1,58 +1,55 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
// var assert = require('assert')
var asn1 = require('asn1');
var asn1 = require('asn1')
var Protocol = require('../protocol');
var Protocol = require('../protocol')
/// --- Globals
///--- Globals
var BerWriter = asn1.BerWriter;
var BerWriter = asn1.BerWriter
var TYPES = {
'and': Protocol.FILTER_AND,
'or': Protocol.FILTER_OR,
'not': Protocol.FILTER_NOT,
'equal': Protocol.FILTER_EQUALITY,
'substring': Protocol.FILTER_SUBSTRINGS,
'ge': Protocol.FILTER_GE,
'le': Protocol.FILTER_LE,
'present': Protocol.FILTER_PRESENT,
'approx': Protocol.FILTER_APPROX,
'ext': Protocol.FILTER_EXT
};
and: Protocol.FILTER_AND,
or: Protocol.FILTER_OR,
not: Protocol.FILTER_NOT,
equal: Protocol.FILTER_EQUALITY,
substring: Protocol.FILTER_SUBSTRINGS,
ge: Protocol.FILTER_GE,
le: Protocol.FILTER_LE,
present: Protocol.FILTER_PRESENT,
approx: Protocol.FILTER_APPROX,
ext: Protocol.FILTER_EXT
}
/// --- API
///--- API
function isFilter(filter) {
function isFilter (filter) {
if (!filter || typeof (filter) !== 'object') {
return false;
return false
}
// Do our best to duck-type it
if (typeof (filter.toBer) === 'function' &&
typeof (filter.matches) === 'function' &&
TYPES[filter.type] !== undefined) {
return true;
return true
}
return false;
return false
}
function mixin(target) {
target.prototype.toBer = function toBer(ber) {
if (!ber || !(ber instanceof BerWriter))
throw new TypeError('ber (BerWriter) required');
function mixin (target) {
target.prototype.toBer = function toBer (ber) {
if (!ber || !(ber instanceof BerWriter)) { throw new TypeError('ber (BerWriter) required') }
ber.startSequence(TYPES[this.type]);
ber = this._toBer(ber);
ber.endSequence();
return ber;
};
ber.startSequence(TYPES[this.type])
ber = this._toBer(ber)
ber.endSequence()
return ber
}
}
module.exports = {
isFilter: isFilter,
mixin: mixin
};
}

View File

@ -1,38 +1,35 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var util = require('util');
var assert = require('assert')
var util = require('util')
var parents = require('ldap-filter');
var parents = require('ldap-filter')
var Filter = require('./filter');
var Filter = require('./filter')
/// --- API
///--- API
function GreaterThanEqualsFilter(options) {
parents.GreaterThanEqualsFilter.call(this, options);
function GreaterThanEqualsFilter (options) {
parents.GreaterThanEqualsFilter.call(this, options)
}
util.inherits(GreaterThanEqualsFilter, parents.GreaterThanEqualsFilter);
Filter.mixin(GreaterThanEqualsFilter);
module.exports = GreaterThanEqualsFilter;
util.inherits(GreaterThanEqualsFilter, parents.GreaterThanEqualsFilter)
Filter.mixin(GreaterThanEqualsFilter)
module.exports = GreaterThanEqualsFilter
GreaterThanEqualsFilter.prototype.parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.attribute = ber.readString().toLowerCase();
this.value = ber.readString();
return true;
};
this.attribute = ber.readString().toLowerCase()
this.value = ber.readString()
return true
}
GreaterThanEqualsFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.attribute);
ber.writeString(this.value);
ber.writeString(this.attribute)
ber.writeString(this.value)
return ber;
};
return ber
}

View File

@ -1,33 +1,30 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var assert = require('assert')
var asn1 = require('asn1');
var asn1 = require('asn1')
var parents = require('ldap-filter');
var parents = require('ldap-filter')
var Protocol = require('../protocol');
var Protocol = require('../protocol')
var Filter = require('./filter');
var AndFilter = require('./and_filter');
var ApproximateFilter = require('./approx_filter');
var EqualityFilter = require('./equality_filter');
var ExtensibleFilter = require('./ext_filter');
var GreaterThanEqualsFilter = require('./ge_filter');
var LessThanEqualsFilter = require('./le_filter');
var NotFilter = require('./not_filter');
var OrFilter = require('./or_filter');
var PresenceFilter = require('./presence_filter');
var SubstringFilter = require('./substr_filter');
var Filter = require('./filter')
var AndFilter = require('./and_filter')
var ApproximateFilter = require('./approx_filter')
var EqualityFilter = require('./equality_filter')
var ExtensibleFilter = require('./ext_filter')
var GreaterThanEqualsFilter = require('./ge_filter')
var LessThanEqualsFilter = require('./le_filter')
var NotFilter = require('./not_filter')
var OrFilter = require('./or_filter')
var PresenceFilter = require('./presence_filter')
var SubstringFilter = require('./substr_filter')
/// --- Globals
var BerReader = asn1.BerReader
///--- Globals
var BerReader = asn1.BerReader;
///--- Internal Parsers
/// --- Internal Parsers
/*
* A filter looks like this coming in:
@ -62,132 +59,137 @@ var BerReader = asn1.BerReader;
* dnAttributes [4] BOOLEAN DEFAULT FALSE
* }
*/
function _parse(ber) {
assert.ok(ber);
function _parse (ber) {
assert.ok(ber)
function parseSet(f) {
var end = ber.offset + ber.length;
while (ber.offset < end)
f.addFilter(_parse(ber));
function parseSet (f) {
var end = ber.offset + ber.length
while (ber.offset < end) { f.addFilter(_parse(ber)) }
}
var f;
var f
var type = ber.readSequence();
var type = ber.readSequence()
switch (type) {
case Protocol.FILTER_AND:
f = new AndFilter()
parseSet(f)
break
case Protocol.FILTER_AND:
f = new AndFilter();
parseSet(f);
break;
case Protocol.FILTER_APPROX:
f = new ApproximateFilter()
f.parse(ber)
break
case Protocol.FILTER_APPROX:
f = new ApproximateFilter();
f.parse(ber);
break;
case Protocol.FILTER_EQUALITY:
f = new EqualityFilter()
f.parse(ber)
return f
case Protocol.FILTER_EQUALITY:
f = new EqualityFilter();
f.parse(ber);
return f;
case Protocol.FILTER_EXT:
f = new ExtensibleFilter()
f.parse(ber)
return f
case Protocol.FILTER_EXT:
f = new ExtensibleFilter();
f.parse(ber);
return f;
case Protocol.FILTER_GE:
f = new GreaterThanEqualsFilter()
f.parse(ber)
return f
case Protocol.FILTER_GE:
f = new GreaterThanEqualsFilter();
f.parse(ber);
return f;
case Protocol.FILTER_LE:
f = new LessThanEqualsFilter()
f.parse(ber)
return f
case Protocol.FILTER_LE:
f = new LessThanEqualsFilter();
f.parse(ber);
return f;
case Protocol.FILTER_NOT:
var _f = _parse(ber)
f = new NotFilter({
filter: _f
})
break
case Protocol.FILTER_NOT:
var _f = _parse(ber);
f = new NotFilter({
filter: _f
});
break;
case Protocol.FILTER_OR:
f = new OrFilter()
parseSet(f)
break
case Protocol.FILTER_OR:
f = new OrFilter();
parseSet(f);
break;
case Protocol.FILTER_PRESENT:
f = new PresenceFilter()
f.parse(ber)
break
case Protocol.FILTER_PRESENT:
f = new PresenceFilter();
f.parse(ber);
break;
case Protocol.FILTER_SUBSTRINGS:
f = new SubstringFilter()
f.parse(ber)
break
case Protocol.FILTER_SUBSTRINGS:
f = new SubstringFilter();
f.parse(ber);
break;
default:
throw new Error('Invalid search filter type: 0x' + type.toString(16));
default:
throw new Error('Invalid search filter type: 0x' + type.toString(16))
}
assert.ok(f);
return f;
assert.ok(f)
return f
}
function cloneFilter(input) {
var child;
function cloneFilter (input) {
var child
if (input.type === 'and' || input.type === 'or') {
child = input.filters.map(cloneFilter);
child = input.filters.map(cloneFilter)
} else if (input.type === 'not') {
child = cloneFilter(input.filter);
child = cloneFilter(input.filter)
}
switch (input.type) {
case 'and':
return new AndFilter({filters: child});
case 'or':
return new OrFilter({filters: child});
case 'not':
return new NotFilter({filter: child});
case 'equal':
return new EqualityFilter(input);
case 'substring':
return new SubstringFilter(input);
case 'ge':
return new GreaterThanEqualsFilter(input);
case 'le':
return new LessThanEqualsFilter(input);
case 'present':
return new PresenceFilter(input);
case 'approx':
return new ApproximateFilter(input);
case 'ext':
return new ExtensibleFilter(input);
default:
throw new Error('invalid filter type:' + input.type);
case 'and':
return new AndFilter({ filters: child })
case 'or':
return new OrFilter({ filters: child })
case 'not':
return new NotFilter({ filter: child })
case 'equal':
return new EqualityFilter(input)
case 'substring':
return new SubstringFilter(input)
case 'ge':
return new GreaterThanEqualsFilter(input)
case 'le':
return new LessThanEqualsFilter(input)
case 'present':
return new PresenceFilter(input)
case 'approx':
return new ApproximateFilter(input)
case 'ext':
return new ExtensibleFilter(input)
default:
throw new Error('invalid filter type:' + input.type)
}
}
function escapedToHex (str) {
return str.replace(/\\([0-9a-f](?![0-9a-f])|[^0-9a-f]|$)/gi, function (match, p1) {
if (!p1) {
return '\\5c'
}
function parseString(str) {
var generic = parents.parse(str);
// The filter object(s) return from ldap-filter.parse lack the toBer/parse
// decoration that native ldapjs filter possess. cloneFilter adds that back.
return cloneFilter(generic);
const hexCode = p1.charCodeAt(0).toString(16)
return '\\' + hexCode
})
}
function parseString (str) {
const hexStr = escapedToHex(str)
const generic = parents.parse(hexStr)
// The filter object(s) return from ldap-filter.parse lack the toBer/parse
// decoration that native ldapjs filter possess. cloneFilter adds that back.
return cloneFilter(generic)
}
///--- API
/// --- API
module.exports = {
parse: function (ber) {
if (!ber || !(ber instanceof BerReader))
throw new TypeError('ber (BerReader) required');
if (!ber || !(ber instanceof BerReader)) { throw new TypeError('ber (BerReader) required') }
return _parse(ber);
return _parse(ber)
},
parseString: parseString,
@ -204,4 +206,4 @@ module.exports = {
OrFilter: OrFilter,
PresenceFilter: PresenceFilter,
SubstringFilter: SubstringFilter
};
}

View File

@ -1,38 +1,35 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var util = require('util');
var assert = require('assert')
var util = require('util')
var parents = require('ldap-filter');
var parents = require('ldap-filter')
var Filter = require('./filter');
var Filter = require('./filter')
/// --- API
///--- API
function LessThanEqualsFilter(options) {
parents.LessThanEqualsFilter.call(this, options);
function LessThanEqualsFilter (options) {
parents.LessThanEqualsFilter.call(this, options)
}
util.inherits(LessThanEqualsFilter, parents.LessThanEqualsFilter);
Filter.mixin(LessThanEqualsFilter);
module.exports = LessThanEqualsFilter;
util.inherits(LessThanEqualsFilter, parents.LessThanEqualsFilter)
Filter.mixin(LessThanEqualsFilter)
module.exports = LessThanEqualsFilter
LessThanEqualsFilter.prototype.parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.attribute = ber.readString().toLowerCase();
this.value = ber.readString();
return true;
};
this.attribute = ber.readString().toLowerCase()
this.value = ber.readString()
return true
}
LessThanEqualsFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.attribute);
ber.writeString(this.value);
ber.writeString(this.attribute)
ber.writeString(this.value)
return ber;
};
return ber
}

View File

@ -1,25 +1,23 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var util = require('util');
var assert = require('assert')
var util = require('util')
var parents = require('ldap-filter');
var parents = require('ldap-filter')
var Filter = require('./filter');
var Filter = require('./filter')
/// --- API
///--- API
function NotFilter(options) {
parents.NotFilter.call(this, options);
function NotFilter (options) {
parents.NotFilter.call(this, options)
}
util.inherits(NotFilter, parents.NotFilter);
Filter.mixin(NotFilter);
module.exports = NotFilter;
util.inherits(NotFilter, parents.NotFilter)
Filter.mixin(NotFilter)
module.exports = NotFilter
NotFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
return this.filter.toBer(ber);
};
return this.filter.toBer(ber)
}

View File

@ -1,29 +1,27 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var util = require('util');
var assert = require('assert')
var util = require('util')
var parents = require('ldap-filter');
var parents = require('ldap-filter')
var Filter = require('./filter');
var Filter = require('./filter')
/// --- API
///--- API
function OrFilter(options) {
parents.OrFilter.call(this, options);
function OrFilter (options) {
parents.OrFilter.call(this, options)
}
util.inherits(OrFilter, parents.OrFilter);
Filter.mixin(OrFilter);
module.exports = OrFilter;
util.inherits(OrFilter, parents.OrFilter)
Filter.mixin(OrFilter)
module.exports = OrFilter
OrFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.filters.forEach(function (f) {
ber = f.toBer(ber);
});
ber = f.toBer(ber)
})
return ber;
};
return ber
}

View File

@ -1,40 +1,36 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var util = require('util');
var assert = require('assert')
var util = require('util')
var parents = require('ldap-filter');
var parents = require('ldap-filter')
var Filter = require('./filter');
var Filter = require('./filter')
/// --- API
///--- API
function PresenceFilter(options) {
parents.PresenceFilter.call(this, options);
function PresenceFilter (options) {
parents.PresenceFilter.call(this, options)
}
util.inherits(PresenceFilter, parents.PresenceFilter);
Filter.mixin(PresenceFilter);
module.exports = PresenceFilter;
util.inherits(PresenceFilter, parents.PresenceFilter)
Filter.mixin(PresenceFilter)
module.exports = PresenceFilter
PresenceFilter.prototype.parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.attribute =
ber.buffer.slice(0, ber.length).toString('utf8').toLowerCase();
ber.buffer.slice(0, ber.length).toString('utf8').toLowerCase()
ber._offset += ber.length;
return true;
};
ber._offset += ber.length
return true
}
PresenceFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
for (var i = 0; i < this.attribute.length; i++)
ber.writeByte(this.attribute.charCodeAt(i));
for (var i = 0; i < this.attribute.length; i++) { ber.writeByte(this.attribute.charCodeAt(i)) }
return ber;
};
return ber
}

View File

@ -1,76 +1,69 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert');
var util = require('util');
var assert = require('assert')
var util = require('util')
var parents = require('ldap-filter');
var parents = require('ldap-filter')
var Filter = require('./filter');
var Filter = require('./filter')
/// --- API
///--- API
function SubstringFilter(options) {
parents.SubstringFilter.call(this, options);
function SubstringFilter (options) {
parents.SubstringFilter.call(this, options)
}
util.inherits(SubstringFilter, parents.SubstringFilter);
Filter.mixin(SubstringFilter);
module.exports = SubstringFilter;
util.inherits(SubstringFilter, parents.SubstringFilter)
Filter.mixin(SubstringFilter)
module.exports = SubstringFilter
SubstringFilter.prototype.parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.attribute = ber.readString().toLowerCase();
ber.readSequence();
var end = ber.offset + ber.length;
this.attribute = ber.readString().toLowerCase()
ber.readSequence()
var end = ber.offset + ber.length
while (ber.offset < end) {
var tag = ber.peek();
var tag = ber.peek()
switch (tag) {
case 0x80: // Initial
this.initial = ber.readString(tag);
if (this.attribute === 'objectclass')
this.initial = this.initial.toLowerCase();
break;
case 0x81: // Any
var anyVal = ber.readString(tag);
if (this.attribute === 'objectclass')
anyVal = anyVal.toLowerCase();
this.any.push(anyVal);
break;
case 0x82: // Final
this.final = ber.readString(tag);
if (this.attribute === 'objectclass')
this.final = this.final.toLowerCase();
break;
default:
throw new Error('Invalid substrings filter type: 0x' + tag.toString(16));
case 0x80: // Initial
this.initial = ber.readString(tag)
if (this.attribute === 'objectclass') { this.initial = this.initial.toLowerCase() }
break
case 0x81: // Any
var anyVal = ber.readString(tag)
if (this.attribute === 'objectclass') { anyVal = anyVal.toLowerCase() }
this.any.push(anyVal)
break
case 0x82: // Final
this.final = ber.readString(tag)
if (this.attribute === 'objectclass') { this.final = this.final.toLowerCase() }
break
default:
throw new Error('Invalid substrings filter type: 0x' + tag.toString(16))
}
}
return true;
};
return true
}
SubstringFilter.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.attribute);
ber.startSequence();
ber.writeString(this.attribute)
ber.startSequence()
if (this.initial)
ber.writeString(this.initial, 0x80);
if (this.initial) { ber.writeString(this.initial, 0x80) }
if (this.any && this.any.length)
if (this.any && this.any.length) {
this.any.forEach(function (s) {
ber.writeString(s, 0x81);
});
ber.writeString(s, 0x81)
})
}
if (this.final)
ber.writeString(this.final, 0x82);
if (this.final) { ber.writeString(this.final, 0x82) }
ber.endSequence();
ber.endSequence()
return ber;
};
return ber
}

View File

@ -1,24 +1,24 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var Logger = require('bunyan');
var logger = require('./logger')
var client = require('./client');
var Attribute = require('./attribute');
var Change = require('./change');
var Protocol = require('./protocol');
var Server = require('./server');
var client = require('./client')
var Attribute = require('./attribute')
var Change = require('./change')
var Protocol = require('./protocol')
var Server = require('./server')
var assert = require('assert');
var controls = require('./controls');
var persistentSearch = require('./persistent_search');
var dn = require('./dn');
var errors = require('./errors');
var filters = require('./filters');
var messages = require('./messages');
var url = require('./url');
var controls = require('./controls')
var persistentSearch = require('./persistent_search')
var dn = require('./dn')
var errors = require('./errors')
var filters = require('./filters')
var messages = require('./messages')
var url = require('./url')
const hasOwnProperty = (target, val) => Object.prototype.hasOwnProperty.call(target, val)
///--- API
/// --- API
module.exports = {
Client: client.Client,
@ -26,21 +26,15 @@ module.exports = {
Server: Server,
createServer: function (options) {
if (options === undefined)
options = {};
if (options === undefined) { options = {} }
if (typeof (options) !== 'object')
throw new TypeError('options (object) required');
if (typeof (options) !== 'object') { throw new TypeError('options (object) required') }
if (!options.log) {
options.log = new Logger({
name: 'ldapjs',
component: 'client',
stream: process.stderr
});
options.log = logger
}
return new Server(options);
return new Server(options)
},
Attribute: Attribute,
@ -59,37 +53,32 @@ module.exports = {
url: url,
parseURL: url.parse
};
}
/// --- Export all the childrenz
///--- Export all the childrenz
var k;
var k
for (k in Protocol) {
if (Protocol.hasOwnProperty(k))
module.exports[k] = Protocol[k];
if (hasOwnProperty(Protocol, k)) { module.exports[k] = Protocol[k] }
}
for (k in messages) {
if (messages.hasOwnProperty(k))
module.exports[k] = messages[k];
if (hasOwnProperty(messages, k)) { module.exports[k] = messages[k] }
}
for (k in controls) {
if (controls.hasOwnProperty(k))
module.exports[k] = controls[k];
if (hasOwnProperty(controls, k)) { module.exports[k] = controls[k] }
}
for (k in filters) {
if (filters.hasOwnProperty(k)) {
if (k !== 'parse' && k !== 'parseString')
module.exports[k] = filters[k];
if (hasOwnProperty(filters, k)) {
if (k !== 'parse' && k !== 'parseString') { module.exports[k] = filters[k] }
}
}
for (k in errors) {
if (errors.hasOwnProperty(k)) {
module.exports[k] = errors[k];
if (hasOwnProperty(errors, k)) {
module.exports[k] = errors[k]
}
}

6
lib/logger.js Normal file
View File

@ -0,0 +1,6 @@
'use strict'
const logger = Object.create(require('abstract-logging'))
logger.child = function () { return logger }
module.exports = logger

View File

@ -1,90 +1,87 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPMessage = require('./message');
var Protocol = require('../protocol');
var LDAPMessage = require('./message')
var Protocol = require('../protocol')
/// --- API
///--- API
function AbandonRequest (options) {
options = options || {}
assert.object(options)
assert.optionalNumber(options.abandonID)
function AbandonRequest(options) {
options = options || {};
assert.object(options);
assert.optionalNumber(options.abandonID);
options.protocolOp = Protocol.LDAP_REQ_ABANDON
LDAPMessage.call(this, options)
options.protocolOp = Protocol.LDAP_REQ_ABANDON;
LDAPMessage.call(this, options);
this.abandonID = options.abandonID || 0;
this.abandonID = options.abandonID || 0
}
util.inherits(AbandonRequest, LDAPMessage);
util.inherits(AbandonRequest, LDAPMessage)
Object.defineProperties(AbandonRequest.prototype, {
type: {
get: function getType() { return 'AbandonRequest'; },
get: function getType () { return 'AbandonRequest' },
configurable: false
}
});
})
AbandonRequest.prototype._parse = function (ber, length) {
assert.ok(ber);
assert.ok(length);
assert.ok(ber)
assert.ok(length)
// What a PITA - have to replicate ASN.1 integer logic to work around the
// way abandon is encoded and the way ldapjs framework handles "normal"
// messages
var buf = ber.buffer;
var offset = 0;
var value = 0;
var buf = ber.buffer
var offset = 0
var value = 0
var fb = buf[offset++];
value = fb & 0x7F;
var fb = buf[offset++]
value = fb & 0x7F
for (var i = 1; i < length; i++) {
value <<= 8;
value |= (buf[offset++] & 0xff);
value <<= 8
value |= (buf[offset++] & 0xff)
}
if ((fb & 0x80) == 0x80)
value = -value;
if ((fb & 0x80) === 0x80) { value = -value }
ber._offset += length;
ber._offset += length
this.abandonID = value;
this.abandonID = value
return true;
};
return true
}
AbandonRequest.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
var i = this.abandonID;
var sz = 4;
var i = this.abandonID
var sz = 4
while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000)) &&
(sz > 1)) {
sz--;
i <<= 8;
sz--
i <<= 8
}
assert.ok(sz <= 4);
assert.ok(sz <= 4)
while (sz-- > 0) {
ber.writeByte((i & 0xff000000) >> 24);
i <<= 8;
ber.writeByte((i & 0xff000000) >> 24)
i <<= 8
}
return ber;
};
return ber
}
AbandonRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.abandonID = this.abandonID;
j.abandonID = this.abandonID
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = AbandonRequest;
module.exports = AbandonRequest

View File

@ -1,36 +1,34 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPMessage = require('./result');
var Protocol = require('../protocol');
var LDAPMessage = require('./result')
// var Protocol = require('../protocol')
/// --- API
///--- API
function AbandonResponse (options) {
options = options || {}
assert.object(options)
function AbandonResponse(options) {
options = options || {};
assert.object(options);
options.protocolOp = 0;
LDAPMessage.call(this, options);
options.protocolOp = 0
LDAPMessage.call(this, options)
}
util.inherits(AbandonResponse, LDAPMessage);
util.inherits(AbandonResponse, LDAPMessage)
Object.defineProperties(AbandonResponse.prototype, {
type: {
get: function getType() { return 'AbandonResponse'; },
get: function getType () { return 'AbandonResponse' },
configurable: false
}
});
})
AbandonResponse.prototype.end = function (status) {};
AbandonResponse.prototype.end = function (status) {}
AbandonResponse.prototype._json = function (j) {
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = AbandonResponse;
module.exports = AbandonResponse

View File

@ -1,130 +1,122 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPMessage = require('./message');
var Attribute = require('../attribute');
var Protocol = require('../protocol');
var lassert = require('../assert');
var LDAPMessage = require('./message')
var Attribute = require('../attribute')
var Protocol = require('../protocol')
var lassert = require('../assert')
/// --- API
///--- API
function AddRequest (options) {
options = options || {}
assert.object(options)
lassert.optionalStringDN(options.entry)
lassert.optionalArrayOfAttribute(options.attributes)
function AddRequest(options) {
options = options || {};
assert.object(options);
lassert.optionalStringDN(options.entry);
lassert.optionalArrayOfAttribute(options.attributes);
options.protocolOp = Protocol.LDAP_REQ_ADD
LDAPMessage.call(this, options)
options.protocolOp = Protocol.LDAP_REQ_ADD;
LDAPMessage.call(this, options);
this.entry = options.entry || null;
this.attributes = options.attributes ? options.attributes.slice(0) : [];
this.entry = options.entry || null
this.attributes = options.attributes ? options.attributes.slice(0) : []
}
util.inherits(AddRequest, LDAPMessage);
util.inherits(AddRequest, LDAPMessage)
Object.defineProperties(AddRequest.prototype, {
type: {
get: function getType() { return 'AddRequest'; },
get: function getType () { return 'AddRequest' },
configurable: false
},
_dn: {
get: function getDN() { return this.entry; },
get: function getDN () { return this.entry },
configurable: false
}
});
})
AddRequest.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.entry = ber.readString();
this.entry = ber.readString()
ber.readSequence();
ber.readSequence()
var end = ber.offset + ber.length;
var end = ber.offset + ber.length
while (ber.offset < end) {
var a = new Attribute();
a.parse(ber);
a.type = a.type.toLowerCase();
var a = new Attribute()
a.parse(ber)
a.type = a.type.toLowerCase()
if (a.type === 'objectclass') {
for (var i = 0; i < a.vals.length; i++)
a.vals[i] = a.vals[i].toLowerCase();
for (var i = 0; i < a.vals.length; i++) { a.vals[i] = a.vals[i].toLowerCase() }
}
this.attributes.push(a);
this.attributes.push(a)
}
this.attributes.sort(Attribute.compare);
return true;
};
this.attributes.sort(Attribute.compare)
return true
}
AddRequest.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.entry.toString());
ber.startSequence();
ber.writeString(this.entry.toString())
ber.startSequence()
this.attributes.forEach(function (a) {
a.toBer(ber);
});
ber.endSequence();
a.toBer(ber)
})
ber.endSequence()
return ber;
};
return ber
}
AddRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.entry = this.entry.toString();
j.attributes = [];
j.entry = this.entry.toString()
j.attributes = []
this.attributes.forEach(function (a) {
j.attributes.push(a.json);
});
j.attributes.push(a.json)
})
return j;
};
return j
}
AddRequest.prototype.indexOf = function (attr) {
if (!attr || typeof (attr) !== 'string')
throw new TypeError('attr (string) required');
if (!attr || typeof (attr) !== 'string') { throw new TypeError('attr (string) required') }
for (var i = 0; i < this.attributes.length; i++) {
if (this.attributes[i].type === attr)
return i;
if (this.attributes[i].type === attr) { return i }
}
return -1;
};
return -1
}
AddRequest.prototype.attributeNames = function () {
var attrs = [];
var attrs = []
for (var i = 0; i < this.attributes.length; i++)
attrs.push(this.attributes[i].type.toLowerCase());
for (var i = 0; i < this.attributes.length; i++) { attrs.push(this.attributes[i].type.toLowerCase()) }
return attrs;
};
return attrs
}
AddRequest.prototype.getAttribute = function (name) {
if (!name || typeof (name) !== 'string')
throw new TypeError('attribute name (string) required');
if (!name || typeof (name) !== 'string') { throw new TypeError('attribute name (string) required') }
name = name.toLowerCase();
name = name.toLowerCase()
for (var i = 0; i < this.attributes.length; i++) {
if (this.attributes[i].type === name)
return this.attributes[i];
if (this.attributes[i].type === name) { return this.attributes[i] }
}
return null;
};
return null
}
AddRequest.prototype.addAttribute = function (attr) {
if (!(attr instanceof Attribute))
throw new TypeError('attribute (Attribute) required');
if (!(attr instanceof Attribute)) { throw new TypeError('attribute (Attribute) required') }
return this.attributes.push(attr);
};
return this.attributes.push(attr)
}
/**
* Returns a "pure" JS representation of this object.
@ -142,30 +134,26 @@ AddRequest.prototype.addAttribute = function (attr) {
* @return {Object} that looks like the above.
*/
AddRequest.prototype.toObject = function () {
var self = this;
var self = this
var obj = {
dn: self.entry ? self.entry.toString() : '',
attributes: {}
};
}
if (!this.attributes || !this.attributes.length)
return obj;
if (!this.attributes || !this.attributes.length) { return obj }
this.attributes.forEach(function (a) {
if (!obj.attributes[a.type])
obj.attributes[a.type] = [];
if (!obj.attributes[a.type]) { obj.attributes[a.type] = [] }
a.vals.forEach(function (v) {
if (obj.attributes[a.type].indexOf(v) === -1)
obj.attributes[a.type].push(v);
});
});
if (obj.attributes[a.type].indexOf(v) === -1) { obj.attributes[a.type].push(v) }
})
})
return obj;
};
return obj
}
/// --- Exports
///--- Exports
module.exports = AddRequest;
module.exports = AddRequest

View File

@ -1,24 +1,22 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPResult = require('./result');
var Protocol = require('../protocol');
var LDAPResult = require('./result')
var Protocol = require('../protocol')
/// --- API
///--- API
function AddResponse (options) {
options = options || {}
assert.object(options)
function AddResponse(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REP_ADD;
LDAPResult.call(this, options);
options.protocolOp = Protocol.LDAP_REP_ADD
LDAPResult.call(this, options)
}
util.inherits(AddResponse, LDAPResult);
util.inherits(AddResponse, LDAPResult)
/// --- Exports
///--- Exports
module.exports = AddResponse;
module.exports = AddResponse

View File

@ -1,88 +1,84 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
var asn1 = require('asn1')
var LDAPMessage = require('./message');
var Protocol = require('../protocol');
var LDAPMessage = require('./message')
var Protocol = require('../protocol')
/// --- Globals
///--- Globals
var Ber = asn1.Ber
var LDAP_BIND_SIMPLE = 'simple'
// var LDAP_BIND_SASL = 'sasl'
var Ber = asn1.Ber;
var LDAP_BIND_SIMPLE = 'simple';
var LDAP_BIND_SASL = 'sasl';
/// --- API
function BindRequest (options) {
options = options || {}
assert.object(options)
///--- API
options.protocolOp = Protocol.LDAP_REQ_BIND
LDAPMessage.call(this, options)
function BindRequest(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REQ_BIND;
LDAPMessage.call(this, options);
this.version = options.version || 0x03;
this.name = options.name || null;
this.authentication = options.authentication || LDAP_BIND_SIMPLE;
this.credentials = options.credentials || '';
this.version = options.version || 0x03
this.name = options.name || null
this.authentication = options.authentication || LDAP_BIND_SIMPLE
this.credentials = options.credentials || ''
}
util.inherits(BindRequest, LDAPMessage);
util.inherits(BindRequest, LDAPMessage)
Object.defineProperties(BindRequest.prototype, {
type: {
get: function getType() { return 'BindRequest'; },
get: function getType () { return 'BindRequest' },
configurable: false
},
_dn: {
get: function getDN() { return this.name; },
get: function getDN () { return this.name },
configurable: false
}
});
})
BindRequest.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.version = ber.readInt();
this.name = ber.readString();
this.version = ber.readInt()
this.name = ber.readString()
var t = ber.peek();
var t = ber.peek()
// TODO add support for SASL et al
if (t !== Ber.Context)
throw new Error('authentication 0x' + t.toString(16) + ' not supported');
if (t !== Ber.Context) { throw new Error('authentication 0x' + t.toString(16) + ' not supported') }
this.authentication = LDAP_BIND_SIMPLE;
this.credentials = ber.readString(Ber.Context);
this.authentication = LDAP_BIND_SIMPLE
this.credentials = ber.readString(Ber.Context)
return true;
};
return true
}
BindRequest.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeInt(this.version);
ber.writeString((this.name || '').toString());
ber.writeInt(this.version)
ber.writeString((this.name || '').toString())
// TODO add support for SASL et al
ber.writeString((this.credentials || ''), Ber.Context);
ber.writeString((this.credentials || ''), Ber.Context)
return ber;
};
return ber
}
BindRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.version = this.version;
j.name = this.name;
j.authenticationType = this.authentication;
j.credentials = this.credentials;
j.version = this.version
j.name = this.name
j.authenticationType = this.authentication
j.credentials = this.credentials
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = BindRequest;
module.exports = BindRequest

View File

@ -1,24 +1,22 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPResult = require('./result');
var Protocol = require('../protocol');
var LDAPResult = require('./result')
var Protocol = require('../protocol')
/// --- API
///--- API
function BindResponse (options) {
options = options || {}
assert.object(options)
function BindResponse(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REP_BIND;
LDAPResult.call(this, options);
options.protocolOp = Protocol.LDAP_REP_BIND
LDAPResult.call(this, options)
}
util.inherits(BindResponse, LDAPResult);
util.inherits(BindResponse, LDAPResult)
/// --- Exports
///--- Exports
module.exports = BindResponse;
module.exports = BindResponse

View File

@ -1,76 +1,74 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPMessage = require('./message');
var Protocol = require('../protocol');
var lassert = require('../assert');
var LDAPMessage = require('./message')
var Protocol = require('../protocol')
var lassert = require('../assert')
/// --- API
///--- API
function CompareRequest (options) {
options = options || {}
assert.object(options)
assert.optionalString(options.attribute)
assert.optionalString(options.value)
lassert.optionalStringDN(options.entry)
function CompareRequest(options) {
options = options || {};
assert.object(options);
assert.optionalString(options.attribute);
assert.optionalString(options.value);
lassert.optionalStringDN(options.entry);
options.protocolOp = Protocol.LDAP_REQ_COMPARE
LDAPMessage.call(this, options)
options.protocolOp = Protocol.LDAP_REQ_COMPARE;
LDAPMessage.call(this, options);
this.entry = options.entry || null;
this.attribute = options.attribute || '';
this.value = options.value || '';
this.entry = options.entry || null
this.attribute = options.attribute || ''
this.value = options.value || ''
}
util.inherits(CompareRequest, LDAPMessage);
util.inherits(CompareRequest, LDAPMessage)
Object.defineProperties(CompareRequest.prototype, {
type: {
get: function getType() { return 'CompareRequest'; },
get: function getType () { return 'CompareRequest' },
configurable: false
},
_dn: {
get: function getDN() { return this.entry; },
get: function getDN () { return this.entry },
configurable: false
}
});
})
CompareRequest.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.entry = ber.readString();
this.entry = ber.readString()
ber.readSequence();
this.attribute = ber.readString().toLowerCase();
this.value = ber.readString();
ber.readSequence()
this.attribute = ber.readString().toLowerCase()
this.value = ber.readString()
return true;
};
return true
}
CompareRequest.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.entry.toString());
ber.startSequence();
ber.writeString(this.attribute);
ber.writeString(this.value);
ber.endSequence();
ber.writeString(this.entry.toString())
ber.startSequence()
ber.writeString(this.attribute)
ber.writeString(this.value)
ber.endSequence()
return ber;
};
return ber
}
CompareRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.entry = this.entry.toString();
j.attribute = this.attribute;
j.value = this.value;
j.entry = this.entry.toString()
j.attribute = this.attribute
j.value = this.value
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = CompareRequest;
module.exports = CompareRequest

View File

@ -1,36 +1,33 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPResult = require('./result');
var Protocol = require('../protocol');
var LDAPResult = require('./result')
var Protocol = require('../protocol')
/// --- API
///--- API
function CompareResponse (options) {
options = options || {}
assert.object(options)
function CompareResponse(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REP_COMPARE;
LDAPResult.call(this, options);
options.protocolOp = Protocol.LDAP_REP_COMPARE
LDAPResult.call(this, options)
}
util.inherits(CompareResponse, LDAPResult);
util.inherits(CompareResponse, LDAPResult)
CompareResponse.prototype.end = function (matches) {
var status = 0x06;
var status = 0x06
if (typeof (matches) === 'boolean') {
if (!matches)
status = 0x05; // Compare false
if (!matches) { status = 0x05 } // Compare false
} else {
status = matches;
status = matches
}
return LDAPResult.prototype.end.call(this, status);
};
return LDAPResult.prototype.end.call(this, status)
}
/// --- Exports
///--- Exports
module.exports = CompareResponse;
module.exports = CompareResponse

View File

@ -1,65 +1,62 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPMessage = require('./message');
var Protocol = require('../protocol');
var lassert = require('../assert');
var LDAPMessage = require('./message')
var Protocol = require('../protocol')
var lassert = require('../assert')
/// --- API
///--- API
function DeleteRequest (options) {
options = options || {}
assert.object(options)
lassert.optionalStringDN(options.entry)
function DeleteRequest(options) {
options = options || {};
assert.object(options);
lassert.optionalStringDN(options.entry);
options.protocolOp = Protocol.LDAP_REQ_DELETE
LDAPMessage.call(this, options)
options.protocolOp = Protocol.LDAP_REQ_DELETE;
LDAPMessage.call(this, options);
this.entry = options.entry || null;
this.entry = options.entry || null
}
util.inherits(DeleteRequest, LDAPMessage);
util.inherits(DeleteRequest, LDAPMessage)
Object.defineProperties(DeleteRequest.prototype, {
type: {
get: function getType() { return 'DeleteRequest'; },
get: function getType () { return 'DeleteRequest' },
configurable: false
},
_dn: {
get: function getDN() { return this.entry; },
get: function getDN () { return this.entry },
configurable: false
}
});
})
DeleteRequest.prototype._parse = function (ber, length) {
assert.ok(ber);
assert.ok(ber)
this.entry = ber.buffer.slice(0, length).toString('utf8');
ber._offset += ber.length;
this.entry = ber.buffer.slice(0, length).toString('utf8')
ber._offset += ber.length
return true;
};
return true
}
DeleteRequest.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
var buf = new Buffer(this.entry.toString());
for (var i = 0; i < buf.length; i++)
ber.writeByte(buf[i]);
var buf = Buffer.from(this.entry.toString())
for (var i = 0; i < buf.length; i++) { ber.writeByte(buf[i]) }
return ber;
};
return ber
}
DeleteRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.entry = this.entry;
j.entry = this.entry
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = DeleteRequest;
module.exports = DeleteRequest

View File

@ -1,24 +1,22 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPResult = require('./result');
var Protocol = require('../protocol');
var LDAPResult = require('./result')
var Protocol = require('../protocol')
/// --- API
///--- API
function DeleteResponse (options) {
options = options || {}
assert.object(options)
function DeleteResponse(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REP_DELETE;
LDAPResult.call(this, options);
options.protocolOp = Protocol.LDAP_REP_DELETE
LDAPResult.call(this, options)
}
util.inherits(DeleteResponse, LDAPResult);
util.inherits(DeleteResponse, LDAPResult)
/// --- Exports
///--- Exports
module.exports = DeleteResponse;
module.exports = DeleteResponse

View File

@ -1,98 +1,116 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPMessage = require('./message');
var Protocol = require('../protocol');
var LDAPMessage = require('./message')
var Protocol = require('../protocol')
/// --- API
///--- API
function ExtendedRequest(options) {
options = options || {};
assert.object(options);
assert.optionalString(options.requestName);
function ExtendedRequest (options) {
options = options || {}
assert.object(options)
assert.optionalString(options.requestName)
if (options.requestValue &&
!(Buffer.isBuffer(options.requestValue) ||
typeof (options.requestValue) === 'string')) {
throw new TypeError('options.requestValue must be a buffer or a string');
throw new TypeError('options.requestValue must be a buffer or a string')
}
options.protocolOp = Protocol.LDAP_REQ_EXTENSION;
LDAPMessage.call(this, options);
options.protocolOp = Protocol.LDAP_REQ_EXTENSION
LDAPMessage.call(this, options)
this.requestName = options.requestName || '';
this.requestValue = options.requestValue;
this.requestName = options.requestName || ''
this.requestValue = options.requestValue
if (Buffer.isBuffer(this.requestValue)) {
this.requestValueBuffer = this.requestValue
} else {
this.requestValueBuffer = Buffer.from(this.requestValue || '', 'utf8')
}
}
util.inherits(ExtendedRequest, LDAPMessage);
util.inherits(ExtendedRequest, LDAPMessage)
Object.defineProperties(ExtendedRequest.prototype, {
type: {
get: function getType() { return 'ExtendedRequest'; },
get: function getType () { return 'ExtendedRequest' },
configurable: false
},
_dn: {
get: function getDN() { return this.requestName; },
get: function getDN () { return this.requestName },
configurable: false
},
name: {
get: function getName() { return this.requestName; },
set: function setName(val) {
assert.string(val);
this.requestName = val;
get: function getName () { return this.requestName },
set: function setName (val) {
assert.string(val)
this.requestName = val
},
configurable: false
},
value: {
get: function getValue() { return this.requestValue; },
set: function setValue(val) {
if (!(Buffer.isBuffer(val) || typeof (val) === 'string'))
throw new TypeError('value must be a buffer or a string');
get: function getValue () { return this.requestValue },
set: function setValue (val) {
if (!(Buffer.isBuffer(val) || typeof (val) === 'string')) { throw new TypeError('value must be a buffer or a string') }
this.requestValue = val;
if (Buffer.isBuffer(val)) {
this.requestValueBuffer = val
} else {
this.requestValueBuffer = Buffer.from(val, 'utf8')
}
this.requestValue = val
},
configurable: false
},
valueBuffer: {
get: function getValueBuffer () {
return this.requestValueBuffer
},
set: function setValueBuffer (val) {
if (!Buffer.isBuffer(val)) { throw new TypeError('valueBuffer must be a buffer') }
this.value = val
},
configurable: false
}
});
})
ExtendedRequest.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.requestName = ber.readString(0x80);
if (ber.peek() === 0x81)
try {
this.requestValue = ber.readString(0x81);
} catch (e) {
this.requestValue = ber.readBuffer(0x81);
}
return true;
};
ExtendedRequest.prototype._toBer = function (ber) {
assert.ok(ber);
ber.writeString(this.requestName, 0x80);
if (Buffer.isBuffer(this.requestValue)) {
ber.writeBuffer(this.requestValue, 0x81);
} else if (typeof (this.requestValue) === 'string') {
ber.writeString(this.requestValue, 0x81);
this.requestName = ber.readString(0x80)
if (ber.peek() === 0x81) {
this.requestValueBuffer = ber.readString(0x81, true)
this.requestValue = this.requestValueBuffer.toString('utf8')
}
return ber;
};
return true
}
ExtendedRequest.prototype._toBer = function (ber) {
assert.ok(ber)
ber.writeString(this.requestName, 0x80)
if (Buffer.isBuffer(this.requestValue)) {
ber.writeBuffer(this.requestValue, 0x81)
} else if (typeof (this.requestValue) === 'string') {
ber.writeString(this.requestValue, 0x81)
}
return ber
}
ExtendedRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.requestName = this.requestName;
j.requestValue = (Buffer.isBuffer(this.requestValue)) ?
this.requestValue.toString('hex') : this.requestValue;
j.requestName = this.requestName
j.requestValue = (Buffer.isBuffer(this.requestValue))
? this.requestValue.toString('hex') : this.requestValue
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = ExtendedRequest;
module.exports = ExtendedRequest

View File

@ -1,94 +1,86 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPResult = require('./result');
var Protocol = require('../protocol');
var LDAPResult = require('./result')
var Protocol = require('../protocol')
/// --- API
///--- API
function ExtendedResponse (options) {
options = options || {}
assert.object(options)
assert.optionalString(options.responseName)
assert.optionalString(options.responsevalue)
function ExtendedResponse(options) {
options = options || {};
assert.object(options);
assert.optionalString(options.responseName);
assert.optionalString(options.responsevalue);
this.responseName = options.responseName || undefined
this.responseValue = options.responseValue || undefined
this.responseName = options.responseName || undefined;
this.responseValue = options.responseValue || undefined;
options.protocolOp = Protocol.LDAP_REP_EXTENSION;
LDAPResult.call(this, options);
options.protocolOp = Protocol.LDAP_REP_EXTENSION
LDAPResult.call(this, options)
}
util.inherits(ExtendedResponse, LDAPResult);
util.inherits(ExtendedResponse, LDAPResult)
Object.defineProperties(ExtendedResponse.prototype, {
type: {
get: function getType() { return 'ExtendedResponse'; },
get: function getType () { return 'ExtendedResponse' },
configurable: false
},
_dn: {
get: function getDN() { return this.responseName; },
get: function getDN () { return this.responseName },
configurable: false
},
name: {
get: function getName() { return this.responseName; },
set: function setName(val) {
assert.string(val);
this.responseName = val;
get: function getName () { return this.responseName },
set: function setName (val) {
assert.string(val)
this.responseName = val
},
configurable: false
},
value: {
get: function getValue() { return this.responseValue; },
get: function getValue () { return this.responseValue },
set: function (val) {
assert.string(val);
this.responseValue = val;
assert.string(val)
this.responseValue = val
},
configurable: false
}
});
})
ExtendedResponse.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
if (!LDAPResult.prototype._parse.call(this, ber))
return false;
if (!LDAPResult.prototype._parse.call(this, ber)) { return false }
if (ber.peek() === 0x8a)
this.responseName = ber.readString(0x8a);
if (ber.peek() === 0x8b)
this.responseValue = ber.readString(0x8b);
if (ber.peek() === 0x8a) { this.responseName = ber.readString(0x8a) }
if (ber.peek() === 0x8b) { this.responseValue = ber.readString(0x8b) }
return true;
};
return true
}
ExtendedResponse.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
if (!LDAPResult.prototype._toBer.call(this, ber))
return false;
if (!LDAPResult.prototype._toBer.call(this, ber)) { return false }
if (this.responseName)
ber.writeString(this.responseName, 0x8a);
if (this.responseValue)
ber.writeString(this.responseValue, 0x8b);
if (this.responseName) { ber.writeString(this.responseName, 0x8a) }
if (this.responseValue) { ber.writeString(this.responseValue, 0x8b) }
return ber;
};
return ber
}
ExtendedResponse.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j = LDAPResult.prototype._json.call(this, j);
j = LDAPResult.prototype._json.call(this, j)
j.responseName = this.responseName;
j.responseValue = this.responseValue;
j.responseName = this.responseName
j.responseValue = this.responseValue
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = ExtendedResponse;
module.exports = ExtendedResponse

View File

@ -1,34 +1,33 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var LDAPMessage = require('./message');
var LDAPResult = require('./result');
var Parser = require('./parser');
var LDAPMessage = require('./message')
var LDAPResult = require('./result')
var Parser = require('./parser')
var AbandonRequest = require('./abandon_request');
var AbandonResponse = require('./abandon_response');
var AddRequest = require('./add_request');
var AddResponse = require('./add_response');
var BindRequest = require('./bind_request');
var BindResponse = require('./bind_response');
var CompareRequest = require('./compare_request');
var CompareResponse = require('./compare_response');
var DeleteRequest = require('./del_request');
var DeleteResponse = require('./del_response');
var ExtendedRequest = require('./ext_request');
var ExtendedResponse = require('./ext_response');
var ModifyRequest = require('./modify_request');
var ModifyResponse = require('./modify_response');
var ModifyDNRequest = require('./moddn_request');
var ModifyDNResponse = require('./moddn_response');
var SearchRequest = require('./search_request');
var SearchEntry = require('./search_entry');
var SearchReference = require('./search_reference');
var SearchResponse = require('./search_response');
var UnbindRequest = require('./unbind_request');
var UnbindResponse = require('./unbind_response');
var AbandonRequest = require('./abandon_request')
var AbandonResponse = require('./abandon_response')
var AddRequest = require('./add_request')
var AddResponse = require('./add_response')
var BindRequest = require('./bind_request')
var BindResponse = require('./bind_response')
var CompareRequest = require('./compare_request')
var CompareResponse = require('./compare_response')
var DeleteRequest = require('./del_request')
var DeleteResponse = require('./del_response')
var ExtendedRequest = require('./ext_request')
var ExtendedResponse = require('./ext_response')
var ModifyRequest = require('./modify_request')
var ModifyResponse = require('./modify_response')
var ModifyDNRequest = require('./moddn_request')
var ModifyDNResponse = require('./moddn_response')
var SearchRequest = require('./search_request')
var SearchEntry = require('./search_entry')
var SearchReference = require('./search_reference')
var SearchResponse = require('./search_response')
var UnbindRequest = require('./unbind_request')
var UnbindResponse = require('./unbind_response')
///--- API
/// --- API
module.exports = {
@ -59,4 +58,4 @@ module.exports = {
UnbindRequest: UnbindRequest,
UnbindResponse: UnbindResponse
};
}

View File

@ -1,50 +1,48 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
var asn1 = require('asn1')
var Control = require('../controls').Control;
var Protocol = require('../protocol');
var logger = require('../logger')
// var Control = require('../controls').Control
// var Protocol = require('../protocol')
/// --- Globals
///--- Globals
var Ber = asn1.Ber;
var BerReader = asn1.BerReader;
var BerWriter = asn1.BerWriter;
var getControl = require('../controls').getControl;
///--- API
// var Ber = asn1.Ber
// var BerReader = asn1.BerReader
var BerWriter = asn1.BerWriter
var getControl = require('../controls').getControl
/// --- API
/**
* LDAPMessage structure.
*
* @param {Object} options stuff.
*/
function LDAPMessage(options) {
assert.object(options);
function LDAPMessage (options) {
assert.object(options)
this.messageID = options.messageID || 0;
this.protocolOp = options.protocolOp || undefined;
this.controls = options.controls ? options.controls.slice(0) : [];
this.messageID = options.messageID || 0
this.protocolOp = options.protocolOp || undefined
this.controls = options.controls ? options.controls.slice(0) : []
this.log = options.log;
this.log = options.log || logger
}
Object.defineProperties(LDAPMessage.prototype, {
id: {
get: function getId() { return this.messageID; },
get: function getId () { return this.messageID },
configurable: false
},
dn: {
get: function getDN() { return this._dn || ''; },
get: function getDN () { return this._dn || '' },
configurable: false
},
type: {
get: function getType() { return 'LDAPMessage'; },
get: function getType () { return 'LDAPMessage' },
configurable: false
},
json: {
@ -52,66 +50,61 @@ Object.defineProperties(LDAPMessage.prototype, {
var out = this._json({
messageID: this.messageID,
protocolOp: this.type
});
out.controls = this.controls;
return out;
})
out.controls = this.controls
return out
},
configurable: false
}
});
})
LDAPMessage.prototype.toString = function () {
return JSON.stringify(this.json);
};
return JSON.stringify(this.json)
}
LDAPMessage.prototype.parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
if (this.log.trace())
this.log.trace('parse: data=%s', util.inspect(ber.buffer));
if (this.log.trace()) { this.log.trace('parse: data=%s', util.inspect(ber.buffer)) }
// Delegate off to the specific type to parse
this._parse(ber, ber.length);
this._parse(ber, ber.length)
// Look for controls
if (ber.peek() === 0xa0) {
ber.readSequence();
var end = ber.offset + ber.length;
ber.readSequence()
var end = ber.offset + ber.length
while (ber.offset < end) {
var c = getControl(ber);
if (c)
this.controls.push(c);
var c = getControl(ber)
if (c) { this.controls.push(c) }
}
}
if (this.log.trace())
this.log.trace('Parsing done: %j', this.json);
return true;
};
if (this.log.trace()) { this.log.trace('Parsing done: %j', this.json) }
return true
}
LDAPMessage.prototype.toBer = function () {
var writer = new BerWriter();
writer.startSequence();
writer.writeInt(this.messageID);
var writer = new BerWriter()
writer.startSequence()
writer.writeInt(this.messageID)
writer.startSequence(this.protocolOp);
if (this._toBer)
writer = this._toBer(writer);
writer.endSequence();
writer.startSequence(this.protocolOp)
if (this._toBer) { writer = this._toBer(writer) }
writer.endSequence()
if (this.controls && this.controls.length) {
writer.startSequence(0xa0);
writer.startSequence(0xa0)
this.controls.forEach(function (c) {
c.toBer(writer);
});
writer.endSequence();
c.toBer(writer)
})
writer.endSequence()
}
writer.endSequence();
return writer.buffer;
};
writer.endSequence()
return writer.buffer
}
/// --- Exports
///--- Exports
module.exports = LDAPMessage;
module.exports = LDAPMessage

View File

@ -1,88 +1,85 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPMessage = require('./message');
var Protocol = require('../protocol');
var dn = require('../dn');
var lassert = require('../assert');
var LDAPMessage = require('./message')
var Protocol = require('../protocol')
var dn = require('../dn')
var lassert = require('../assert')
/// --- API
///--- API
function ModifyDNRequest (options) {
options = options || {}
assert.object(options)
assert.optionalBool(options.deleteOldRdn)
lassert.optionalStringDN(options.entry)
lassert.optionalDN(options.newRdn)
lassert.optionalDN(options.newSuperior)
function ModifyDNRequest(options) {
options = options || {};
assert.object(options);
assert.optionalBool(options.deleteOldRdn);
lassert.optionalStringDN(options.entry);
lassert.optionalDN(options.newRdn);
lassert.optionalDN(options.newSuperior);
options.protocolOp = Protocol.LDAP_REQ_MODRDN
LDAPMessage.call(this, options)
options.protocolOp = Protocol.LDAP_REQ_MODRDN;
LDAPMessage.call(this, options);
this.entry = options.entry || null;
this.newRdn = options.newRdn || null;
this.deleteOldRdn = options.deleteOldRdn || true;
this.newSuperior = options.newSuperior || null;
this.entry = options.entry || null
this.newRdn = options.newRdn || null
this.deleteOldRdn = options.deleteOldRdn || true
this.newSuperior = options.newSuperior || null
}
util.inherits(ModifyDNRequest, LDAPMessage);
util.inherits(ModifyDNRequest, LDAPMessage)
Object.defineProperties(ModifyDNRequest.prototype, {
type: {
get: function getType() { return 'ModifyDNRequest'; },
get: function getType () { return 'ModifyDNRequest' },
configurable: false
},
_dn: {
get: function getDN() { return this.entry; },
get: function getDN () { return this.entry },
configurable: false
}
});
})
ModifyDNRequest.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.entry = ber.readString();
this.newRdn = dn.parse(ber.readString());
this.deleteOldRdn = ber.readBoolean();
if (ber.peek() === 0x80)
this.newSuperior = dn.parse(ber.readString(0x80));
this.entry = ber.readString()
this.newRdn = dn.parse(ber.readString())
this.deleteOldRdn = ber.readBoolean()
if (ber.peek() === 0x80) { this.newSuperior = dn.parse(ber.readString(0x80)) }
return true;
};
return true
}
ModifyDNRequest.prototype._toBer = function (ber) {
//assert.ok(ber);
// assert.ok(ber);
ber.writeString(this.entry.toString());
ber.writeString(this.newRdn.toString());
ber.writeBoolean(this.deleteOldRdn);
ber.writeString(this.entry.toString())
ber.writeString(this.newRdn.toString())
ber.writeBoolean(this.deleteOldRdn)
if (this.newSuperior) {
var s = this.newSuperior.toString();
var len = Buffer.byteLength(s);
var s = this.newSuperior.toString()
var len = Buffer.byteLength(s)
ber.writeByte(0x80); // MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG
ber.writeByte(len);
ber._ensure(len);
ber._buf.write(s, ber._offset);
ber._offset += len;
ber.writeByte(0x80) // MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG
ber.writeByte(len)
ber._ensure(len)
ber._buf.write(s, ber._offset)
ber._offset += len
}
return ber;
};
return ber
}
ModifyDNRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.entry = this.entry.toString();
j.newRdn = this.newRdn.toString();
j.deleteOldRdn = this.deleteOldRdn;
j.newSuperior = this.newSuperior ? this.newSuperior.toString() : '';
j.entry = this.entry.toString()
j.newRdn = this.newRdn.toString()
j.deleteOldRdn = this.deleteOldRdn
j.newSuperior = this.newSuperior ? this.newSuperior.toString() : ''
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = ModifyDNRequest;
module.exports = ModifyDNRequest

View File

@ -1,24 +1,22 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPResult = require('./result');
var Protocol = require('../protocol');
var LDAPResult = require('./result')
var Protocol = require('../protocol')
/// --- API
///--- API
function ModifyDNResponse (options) {
options = options || {}
assert.object(options)
function ModifyDNResponse(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REP_MODRDN;
LDAPResult.call(this, options);
options.protocolOp = Protocol.LDAP_REP_MODRDN
LDAPResult.call(this, options)
}
util.inherits(ModifyDNResponse, LDAPResult);
util.inherits(ModifyDNResponse, LDAPResult)
/// --- Exports
///--- Exports
module.exports = ModifyDNResponse;
module.exports = ModifyDNResponse

View File

@ -1,85 +1,83 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPMessage = require('./message');
var Change = require('../change');
var Protocol = require('../protocol');
var lassert = require('../assert');
var LDAPMessage = require('./message')
var Change = require('../change')
var Protocol = require('../protocol')
var lassert = require('../assert')
/// --- API
///--- API
function ModifyRequest (options) {
options = options || {}
assert.object(options)
lassert.optionalStringDN(options.object)
lassert.optionalArrayOfAttribute(options.attributes)
function ModifyRequest(options) {
options = options || {};
assert.object(options);
lassert.optionalStringDN(options.object);
lassert.optionalArrayOfAttribute(options.attributes);
options.protocolOp = Protocol.LDAP_REQ_MODIFY
LDAPMessage.call(this, options)
options.protocolOp = Protocol.LDAP_REQ_MODIFY;
LDAPMessage.call(this, options);
this.object = options.object || null;
this.changes = options.changes ? options.changes.slice(0) : [];
this.object = options.object || null
this.changes = options.changes ? options.changes.slice(0) : []
}
util.inherits(ModifyRequest, LDAPMessage);
util.inherits(ModifyRequest, LDAPMessage)
Object.defineProperties(ModifyRequest.prototype, {
type: {
get: function getType() { return 'ModifyRequest'; },
get: function getType () { return 'ModifyRequest' },
configurable: false
},
_dn: {
get: function getDN() { return this.object; },
get: function getDN () { return this.object },
configurable: false
}
});
})
ModifyRequest.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.object = ber.readString();
this.object = ber.readString()
ber.readSequence();
var end = ber.offset + ber.length;
ber.readSequence()
var end = ber.offset + ber.length
while (ber.offset < end) {
var c = new Change();
c.parse(ber);
c.modification.type = c.modification.type.toLowerCase();
this.changes.push(c);
var c = new Change()
c.parse(ber)
c.modification.type = c.modification.type.toLowerCase()
this.changes.push(c)
}
this.changes.sort(Change.compare);
return true;
};
this.changes.sort(Change.compare)
return true
}
ModifyRequest.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.object.toString());
ber.startSequence();
ber.writeString(this.object.toString())
ber.startSequence()
this.changes.forEach(function (c) {
c.toBer(ber);
});
ber.endSequence();
c.toBer(ber)
})
ber.endSequence()
return ber;
};
return ber
}
ModifyRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.object = this.object;
j.changes = [];
j.object = this.object
j.changes = []
this.changes.forEach(function (c) {
j.changes.push(c.json);
});
j.changes.push(c.json)
})
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = ModifyRequest;
module.exports = ModifyRequest

View File

@ -1,24 +1,22 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPResult = require('./result');
var Protocol = require('../protocol');
var LDAPResult = require('./result')
var Protocol = require('../protocol')
/// --- API
///--- API
function ModifyResponse (options) {
options = options || {}
assert.object(options)
function ModifyResponse(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REP_MODIFY;
LDAPResult.call(this, options);
options.protocolOp = Protocol.LDAP_REP_MODIFY
LDAPResult.call(this, options)
}
util.inherits(ModifyResponse, LDAPResult);
util.inherits(ModifyResponse, LDAPResult)
/// --- Exports
///--- Exports
module.exports = ModifyResponse;
module.exports = ModifyResponse

View File

@ -1,228 +1,221 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var EventEmitter = require('events').EventEmitter
var util = require('util')
var assert = require('assert-plus');
var asn1 = require('asn1');
var VError = require('verror').VError;
var assert = require('assert-plus')
var asn1 = require('asn1')
// var VError = require('verror').VError
var logger = require('../logger')
var AbandonRequest = require('./abandon_request');
var AddRequest = require('./add_request');
var AddResponse = require('./add_response');
var BindRequest = require('./bind_request');
var BindResponse = require('./bind_response');
var CompareRequest = require('./compare_request');
var CompareResponse = require('./compare_response');
var DeleteRequest = require('./del_request');
var DeleteResponse = require('./del_response');
var ExtendedRequest = require('./ext_request');
var ExtendedResponse = require('./ext_response');
var ModifyRequest = require('./modify_request');
var ModifyResponse = require('./modify_response');
var ModifyDNRequest = require('./moddn_request');
var ModifyDNResponse = require('./moddn_response');
var SearchRequest = require('./search_request');
var SearchEntry = require('./search_entry');
var SearchReference = require('./search_reference');
var SearchResponse = require('./search_response');
var UnbindRequest = require('./unbind_request');
var UnbindResponse = require('./unbind_response');
var AbandonRequest = require('./abandon_request')
var AddRequest = require('./add_request')
var AddResponse = require('./add_response')
var BindRequest = require('./bind_request')
var BindResponse = require('./bind_response')
var CompareRequest = require('./compare_request')
var CompareResponse = require('./compare_response')
var DeleteRequest = require('./del_request')
var DeleteResponse = require('./del_response')
var ExtendedRequest = require('./ext_request')
var ExtendedResponse = require('./ext_response')
var ModifyRequest = require('./modify_request')
var ModifyResponse = require('./modify_response')
var ModifyDNRequest = require('./moddn_request')
var ModifyDNResponse = require('./moddn_response')
var SearchRequest = require('./search_request')
var SearchEntry = require('./search_entry')
var SearchReference = require('./search_reference')
var SearchResponse = require('./search_response')
var UnbindRequest = require('./unbind_request')
// var UnbindResponse = require('./unbind_response')
var LDAPResult = require('./result');
var Message = require('./message');
var LDAPResult = require('./result')
// var Message = require('./message')
var Protocol = require('../protocol');
var Protocol = require('../protocol')
/// --- Globals
///--- Globals
// var Ber = asn1.Ber
var BerReader = asn1.BerReader
var Ber = asn1.Ber;
var BerReader = asn1.BerReader;
/// --- API
function Parser (options = {}) {
assert.object(options)
///--- API
EventEmitter.call(this)
function Parser(options) {
assert.object(options);
assert.object(options.log);
EventEmitter.call(this);
this.buffer = null;
this.log = options.log;
this.buffer = null
this.log = options.log || logger
}
util.inherits(Parser, EventEmitter);
util.inherits(Parser, EventEmitter)
Parser.prototype.write = function (data) {
if (!data || !Buffer.isBuffer(data))
throw new TypeError('data (buffer) required');
if (!data || !Buffer.isBuffer(data)) { throw new TypeError('data (buffer) required') }
var nextMessage = null;
var self = this;
var nextMessage = null
var self = this
function end() {
if (nextMessage)
return self.write(nextMessage);
function end () {
if (nextMessage) { return self.write(nextMessage) }
return true;
return true
}
self.buffer = (self.buffer ? Buffer.concat([self.buffer, data]) : data);
self.buffer = (self.buffer ? Buffer.concat([self.buffer, data]) : data)
var ber = new BerReader(self.buffer);
var ber = new BerReader(self.buffer)
var foundSeq = false;
var foundSeq = false
try {
foundSeq = ber.readSequence();
foundSeq = ber.readSequence()
} catch (e) {
this.emit('error', e);
this.emit('error', e)
}
if (!foundSeq || ber.remain < ber.length) {
// ENOTENOUGH
return false;
return false
} else if (ber.remain > ber.length) {
// ETOOMUCH
// This is sort of ugly, but allows us to make miminal copies
nextMessage = self.buffer.slice(ber.offset + ber.length);
ber._size = ber.offset + ber.length;
assert.equal(ber.remain, ber.length);
nextMessage = self.buffer.slice(ber.offset + ber.length)
ber._size = ber.offset + ber.length
assert.equal(ber.remain, ber.length)
}
// If we're here, ber holds the message, and nextMessage is temporarily
// pointing at the next sequence of data (if it exists)
self.buffer = null;
self.buffer = null
var message;
var message
try {
// Bail here if peer isn't speaking protocol at all
message = this.getMessage(ber);
message = this.getMessage(ber)
if (!message) {
return end();
return end()
}
message.parse(ber);
message.parse(ber)
} catch (e) {
this.emit('error', e, message);
return false;
this.emit('error', e, message)
return false
}
this.emit('message', message);
return end();
};
this.emit('message', message)
return end()
}
Parser.prototype.getMessage = function (ber) {
assert.ok(ber);
assert.ok(ber)
var self = this;
var self = this
var messageID = ber.readInt();
var type = ber.readSequence();
var messageID = ber.readInt()
var type = ber.readSequence()
var Message;
var Message
switch (type) {
case Protocol.LDAP_REQ_ABANDON:
Message = AbandonRequest
break
case Protocol.LDAP_REQ_ABANDON:
Message = AbandonRequest;
break;
case Protocol.LDAP_REQ_ADD:
Message = AddRequest
break
case Protocol.LDAP_REQ_ADD:
Message = AddRequest;
break;
case Protocol.LDAP_REP_ADD:
Message = AddResponse
break
case Protocol.LDAP_REP_ADD:
Message = AddResponse;
break;
case Protocol.LDAP_REQ_BIND:
Message = BindRequest
break
case Protocol.LDAP_REQ_BIND:
Message = BindRequest;
break;
case Protocol.LDAP_REP_BIND:
Message = BindResponse
break
case Protocol.LDAP_REP_BIND:
Message = BindResponse;
break;
case Protocol.LDAP_REQ_COMPARE:
Message = CompareRequest
break
case Protocol.LDAP_REQ_COMPARE:
Message = CompareRequest;
break;
case Protocol.LDAP_REP_COMPARE:
Message = CompareResponse
break
case Protocol.LDAP_REP_COMPARE:
Message = CompareResponse;
break;
case Protocol.LDAP_REQ_DELETE:
Message = DeleteRequest
break
case Protocol.LDAP_REQ_DELETE:
Message = DeleteRequest;
break;
case Protocol.LDAP_REP_DELETE:
Message = DeleteResponse
break
case Protocol.LDAP_REP_DELETE:
Message = DeleteResponse;
break;
case Protocol.LDAP_REQ_EXTENSION:
Message = ExtendedRequest
break
case Protocol.LDAP_REQ_EXTENSION:
Message = ExtendedRequest;
break;
case Protocol.LDAP_REP_EXTENSION:
Message = ExtendedResponse
break
case Protocol.LDAP_REP_EXTENSION:
Message = ExtendedResponse;
break;
case Protocol.LDAP_REQ_MODIFY:
Message = ModifyRequest
break
case Protocol.LDAP_REQ_MODIFY:
Message = ModifyRequest;
break;
case Protocol.LDAP_REP_MODIFY:
Message = ModifyResponse
break
case Protocol.LDAP_REP_MODIFY:
Message = ModifyResponse;
break;
case Protocol.LDAP_REQ_MODRDN:
Message = ModifyDNRequest
break
case Protocol.LDAP_REQ_MODRDN:
Message = ModifyDNRequest;
break;
case Protocol.LDAP_REP_MODRDN:
Message = ModifyDNResponse
break
case Protocol.LDAP_REP_MODRDN:
Message = ModifyDNResponse;
break;
case Protocol.LDAP_REQ_SEARCH:
Message = SearchRequest
break
case Protocol.LDAP_REQ_SEARCH:
Message = SearchRequest;
break;
case Protocol.LDAP_REP_SEARCH_ENTRY:
Message = SearchEntry
break
case Protocol.LDAP_REP_SEARCH_ENTRY:
Message = SearchEntry;
break;
case Protocol.LDAP_REP_SEARCH_REF:
Message = SearchReference
break
case Protocol.LDAP_REP_SEARCH_REF:
Message = SearchReference;
break;
case Protocol.LDAP_REP_SEARCH:
Message = SearchResponse
break
case Protocol.LDAP_REP_SEARCH:
Message = SearchResponse;
break;
case Protocol.LDAP_REQ_UNBIND:
Message = UnbindRequest
break
case Protocol.LDAP_REQ_UNBIND:
Message = UnbindRequest;
break;
default:
this.emit('error',
new Error('Op 0x' + (type ? type.toString(16) : '??') +
default:
this.emit('error',
new Error('Op 0x' + (type ? type.toString(16) : '??') +
' not supported'),
new LDAPResult({
messageID: messageID,
protocolOp: type || Protocol.LDAP_REP_EXTENSION
}));
new LDAPResult({
messageID: messageID,
protocolOp: type || Protocol.LDAP_REP_EXTENSION
}))
return false;
return false
}
return new Message({
messageID: messageID,
log: self.log
});
};
})
}
/// --- Exports
///--- Exports
module.exports = Parser;
module.exports = Parser

View File

@ -1,65 +1,61 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
// var asn1 = require('asn1')
var dtrace = require('../dtrace');
var LDAPMessage = require('./message');
var Protocol = require('../protocol');
var dtrace = require('../dtrace')
var LDAPMessage = require('./message')
var Protocol = require('../protocol')
/// --- Globals
///--- Globals
// var Ber = asn1.Ber
// var BerWriter = asn1.BerWriter
var Ber = asn1.Ber;
var BerWriter = asn1.BerWriter;
/// --- API
function LDAPResult (options) {
options = options || {}
assert.object(options)
assert.optionalNumber(options.status)
assert.optionalString(options.matchedDN)
assert.optionalString(options.errorMessage)
assert.optionalArrayOfString(options.referrals)
///--- API
LDAPMessage.call(this, options)
function LDAPResult(options) {
options = options || {};
assert.object(options);
assert.optionalNumber(options.status);
assert.optionalString(options.matchedDN);
assert.optionalString(options.errorMessage);
assert.optionalArrayOfString(options.referrals);
this.status = options.status || 0 // LDAP SUCCESS
this.matchedDN = options.matchedDN || ''
this.errorMessage = options.errorMessage || ''
this.referrals = options.referrals || []
LDAPMessage.call(this, options);
this.status = options.status || 0; // LDAP SUCCESS
this.matchedDN = options.matchedDN || '';
this.errorMessage = options.errorMessage || '';
this.referrals = options.referrals || [];
this.connection = options.connection || null;
this.connection = options.connection || null
}
util.inherits(LDAPResult, LDAPMessage);
util.inherits(LDAPResult, LDAPMessage)
Object.defineProperties(LDAPResult.prototype, {
type: {
get: function getType() { return 'LDAPResult'; },
get: function getType () { return 'LDAPResult' },
configurable: false
}
});
})
LDAPResult.prototype.end = function (status) {
assert.ok(this.connection);
assert.ok(this.connection)
if (typeof (status) === 'number')
this.status = status;
if (typeof (status) === 'number') { this.status = status }
var ber = this.toBer();
if (this.log.debug())
this.log.debug('%s: sending: %j', this.connection.ldap.id, this.json);
var ber = this.toBer()
if (this.log.debug()) { this.log.debug('%s: sending: %j', this.connection.ldap.id, this.json) }
try {
var self = this;
this.connection.write(ber);
var self = this
this.connection.write(ber)
if (self._dtraceOp && self._dtraceId) {
dtrace.fire('server-' + self._dtraceOp + '-done', function () {
var c = self.connection || {ldap: {}};
var c = self.connection || { ldap: {} }
return [
self._dtraceId || 0,
(c.remoteAddress || ''),
@ -67,63 +63,59 @@ LDAPResult.prototype.end = function (status) {
(self.requestDN ? self.requestDN.toString() : ''),
status || self.status,
self.errorMessage
];
});
]
})
}
} catch (e) {
this.log.warn(e, '%s failure to write message %j',
this.connection.ldap.id, this.json);
this.connection.ldap.id, this.json)
}
};
}
LDAPResult.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.status = ber.readEnumeration();
this.matchedDN = ber.readString();
this.errorMessage = ber.readString();
this.status = ber.readEnumeration()
this.matchedDN = ber.readString()
this.errorMessage = ber.readString()
var t = ber.peek();
var t = ber.peek()
if (t === Protocol.LDAP_REP_REFERRAL) {
var end = ber.offset + ber.length;
while (ber.offset < end)
this.referrals.push(ber.readString());
var end = ber.offset + ber.length
while (ber.offset < end) { this.referrals.push(ber.readString()) }
}
return true;
};
return true
}
LDAPResult.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeEnumeration(this.status);
ber.writeString(this.matchedDN || '');
ber.writeString(this.errorMessage || '');
ber.writeEnumeration(this.status)
ber.writeString(this.matchedDN || '')
ber.writeString(this.errorMessage || '')
if (this.referrals.length) {
ber.startSequence(Protocol.LDAP_REP_REFERRAL);
ber.writeStringArray(this.referrals);
ber.endSequence();
ber.startSequence(Protocol.LDAP_REP_REFERRAL)
ber.writeStringArray(this.referrals)
ber.endSequence()
}
return ber;
};
return ber
}
LDAPResult.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.status = this.status;
j.matchedDN = this.matchedDN;
j.errorMessage = this.errorMessage;
j.referrals = this.referrals;
j.status = this.status
j.matchedDN = this.matchedDN
j.errorMessage = this.errorMessage
j.referrals = this.referrals
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = LDAPResult;
module.exports = LDAPResult

View File

@ -1,196 +1,187 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
// var asn1 = require('asn1')
var LDAPMessage = require('./message');
var Attribute = require('../attribute');
var Protocol = require('../protocol');
var lassert = require('../assert');
var LDAPMessage = require('./message')
var Attribute = require('../attribute')
var Protocol = require('../protocol')
var lassert = require('../assert')
/// --- Globals
///--- Globals
// var BerWriter = asn1.BerWriter
var BerWriter = asn1.BerWriter;
/// --- API
function SearchEntry (options) {
options = options || {}
assert.object(options)
lassert.optionalStringDN(options.objectName)
///--- API
options.protocolOp = Protocol.LDAP_REP_SEARCH_ENTRY
LDAPMessage.call(this, options)
function SearchEntry(options) {
options = options || {};
assert.object(options);
lassert.optionalStringDN(options.objectName);
options.protocolOp = Protocol.LDAP_REP_SEARCH_ENTRY;
LDAPMessage.call(this, options);
this.objectName = options.objectName || null;
this.setAttributes(options.attributes || []);
this.objectName = options.objectName || null
this.setAttributes(options.attributes || [])
}
util.inherits(SearchEntry, LDAPMessage);
util.inherits(SearchEntry, LDAPMessage)
Object.defineProperties(SearchEntry.prototype, {
type: {
get: function getType() { return 'SearchEntry'; },
get: function getType () { return 'SearchEntry' },
configurable: false
},
_dn: {
get: function getDN() { return this.objectName; },
get: function getDN () { return this.objectName },
configurable: false
},
object: {
get: function getObject() {
get: function getObject () {
var obj = {
dn: this.dn.toString(),
controls: []
};
}
this.attributes.forEach(function (a) {
if (a.vals && a.vals.length) {
if (a.vals.length > 1) {
obj[a.type] = a.vals.slice();
obj[a.type] = a.vals.slice()
} else {
obj[a.type] = a.vals[0];
obj[a.type] = a.vals[0]
}
} else {
obj[a.type] = [];
obj[a.type] = []
}
});
})
this.controls.forEach(function (element, index, array) {
obj.controls.push(element.json);
});
return obj;
obj.controls.push(element.json)
})
return obj
},
configurable: false
},
raw: {
get: function getRaw() {
get: function getRaw () {
var obj = {
dn: this.dn.toString(),
controls: []
};
}
this.attributes.forEach(function (a) {
if (a.buffers && a.buffers.length) {
if (a.buffers.length > 1) {
obj[a.type] = a.buffers.slice();
obj[a.type] = a.buffers.slice()
} else {
obj[a.type] = a.buffers[0];
obj[a.type] = a.buffers[0]
}
} else {
obj[a.type] = [];
obj[a.type] = []
}
});
})
this.controls.forEach(function (element, index, array) {
obj.controls.push(element.json);
});
return obj;
obj.controls.push(element.json)
})
return obj
},
configurable: false
}
});
})
SearchEntry.prototype.addAttribute = function (attr) {
if (!attr || typeof (attr) !== 'object')
throw new TypeError('attr (attribute) required');
if (!attr || typeof (attr) !== 'object') { throw new TypeError('attr (attribute) required') }
this.attributes.push(attr);
};
this.attributes.push(attr)
}
SearchEntry.prototype.toObject = function () {
return this.object;
};
return this.object
}
SearchEntry.prototype.fromObject = function (obj) {
if (typeof (obj) !== 'object')
throw new TypeError('object required');
if (typeof (obj) !== 'object') { throw new TypeError('object required') }
var self = this;
if (obj.controls)
this.controls = obj.controls;
var self = this
if (obj.controls) { this.controls = obj.controls }
if (obj.attributes)
obj = obj.attributes;
this.attributes = [];
if (obj.attributes) { obj = obj.attributes }
this.attributes = []
Object.keys(obj).forEach(function (k) {
self.attributes.push(new Attribute({type: k, vals: obj[k]}));
});
self.attributes.push(new Attribute({ type: k, vals: obj[k] }))
})
return true;
};
return true
}
SearchEntry.prototype.setAttributes = function (obj) {
if (typeof (obj) !== 'object')
throw new TypeError('object required');
if (typeof (obj) !== 'object') { throw new TypeError('object required') }
if (Array.isArray(obj)) {
obj.forEach(function (a) {
if (!Attribute.isAttribute(a))
throw new TypeError('entry must be an Array of Attributes');
});
this.attributes = obj;
if (!Attribute.isAttribute(a)) { throw new TypeError('entry must be an Array of Attributes') }
})
this.attributes = obj
} else {
var self = this;
var self = this
self.attributes = [];
self.attributes = []
Object.keys(obj).forEach(function (k) {
var attr = new Attribute({type: k});
var attr = new Attribute({ type: k })
if (Array.isArray(obj[k])) {
obj[k].forEach(function (v) {
attr.addValue(v.toString());
});
attr.addValue(v.toString())
})
} else {
attr.addValue(obj[k].toString());
attr.addValue(obj[k].toString())
}
self.attributes.push(attr);
});
self.attributes.push(attr)
})
}
};
}
SearchEntry.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.objectName = this.objectName.toString();
j.attributes = [];
j.objectName = this.objectName.toString()
j.attributes = []
this.attributes.forEach(function (a) {
j.attributes.push(a.json || a);
});
j.attributes.push(a.json || a)
})
return j;
};
return j
}
SearchEntry.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.objectName = ber.readString();
assert.ok(ber.readSequence());
this.objectName = ber.readString()
assert.ok(ber.readSequence())
var end = ber.offset + ber.length;
var end = ber.offset + ber.length
while (ber.offset < end) {
var a = new Attribute();
a.parse(ber);
this.attributes.push(a);
var a = new Attribute()
a.parse(ber)
this.attributes.push(a)
}
return true;
};
return true
}
SearchEntry.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.objectName.toString());
ber.startSequence();
ber.writeString(this.objectName.toString())
ber.startSequence()
this.attributes.forEach(function (a) {
// This may or may not be an attribute
ber = Attribute.toBer(a, ber);
});
ber.endSequence();
ber = Attribute.toBer(a, ber)
})
ber.endSequence()
return ber;
};
return ber
}
/// --- Exports
///--- Exports
module.exports = SearchEntry;
module.exports = SearchEntry

View File

@ -1,105 +1,101 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
// var asn1 = require('asn1')
var LDAPMessage = require('./message');
var Protocol = require('../protocol');
var dn = require('../dn');
var url = require('../url');
var LDAPMessage = require('./message')
var Protocol = require('../protocol')
var dn = require('../dn')
var url = require('../url')
/// --- Globals
///--- Globals
// var BerWriter = asn1.BerWriter
var parseURL = url.parse
var BerWriter = asn1.BerWriter;
var parseURL = url.parse;
/// --- API
function SearchReference (options) {
options = options || {}
assert.object(options)
///--- API
options.protocolOp = Protocol.LDAP_REP_SEARCH_REF
LDAPMessage.call(this, options)
function SearchReference(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REP_SEARCH_REF;
LDAPMessage.call(this, options);
this.uris = options.uris || [];
this.uris = options.uris || []
}
util.inherits(SearchReference, LDAPMessage);
util.inherits(SearchReference, LDAPMessage)
Object.defineProperties(SearchReference.prototype, {
type: {
get: function getType() { return 'SearchReference'; },
get: function getType () { return 'SearchReference' },
configurable: false
},
_dn: {
get: function getDN() { return new dn.DN(''); },
get: function getDN () { return new dn.DN('') },
configurable: false
},
object: {
get: function getObject() {
get: function getObject () {
return {
dn: this.dn.toString(),
uris: this.uris.slice()
};
}
},
configurable: false
},
urls: {
get: function getUrls() { return this.uris; },
set: function setUrls(val) {
assert.ok(val);
assert.ok(Array.isArray(val));
this.uris = val.slice();
get: function getUrls () { return this.uris },
set: function setUrls (val) {
assert.ok(val)
assert.ok(Array.isArray(val))
this.uris = val.slice()
},
configurable: false
}
});
})
SearchReference.prototype.toObject = function () {
return this.object;
};
return this.object
}
SearchReference.prototype.fromObject = function (obj) {
if (typeof (obj) !== 'object')
throw new TypeError('object required');
if (typeof (obj) !== 'object') { throw new TypeError('object required') }
this.uris = obj.uris ? obj.uris.slice() : [];
this.uris = obj.uris ? obj.uris.slice() : []
return true;
};
return true
}
SearchReference.prototype._json = function (j) {
assert.ok(j);
j.uris = this.uris.slice();
return j;
};
assert.ok(j)
j.uris = this.uris.slice()
return j
}
SearchReference.prototype._parse = function (ber, length) {
assert.ok(ber);
assert.ok(ber)
while (ber.offset < length) {
var _url = ber.readString();
parseURL(_url);
this.uris.push(_url);
var _url = ber.readString()
parseURL(_url)
this.uris.push(_url)
}
return true;
};
return true
}
SearchReference.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.uris.forEach(function (u) {
ber.writeString(u.href || u);
});
ber.writeString(u.href || u)
})
return ber;
};
return ber
}
/// --- Exports
///--- Exports
module.exports = SearchReference;
module.exports = SearchReference

View File

@ -1,150 +1,152 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var asn1 = require('asn1');
var asn1 = require('asn1')
var LDAPMessage = require('./message');
var LDAPResult = require('./result');
var dn = require('../dn');
var filters = require('../filters');
var Protocol = require('../protocol');
var LDAPMessage = require('./message')
// var LDAPResult = require('./result')
var dn = require('../dn')
var filters = require('../filters')
var Protocol = require('../protocol')
/// --- Globals
///--- Globals
var Ber = asn1.Ber
var Ber = asn1.Ber;
/// --- API
function SearchRequest (options) {
options = options || {}
assert.object(options)
///--- API
function SearchRequest(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REQ_SEARCH;
LDAPMessage.call(this, options);
options.protocolOp = Protocol.LDAP_REQ_SEARCH
LDAPMessage.call(this, options)
if (options.baseObject !== undefined) {
this.baseObject = options.baseObject;
this.baseObject = options.baseObject
} else {
this.baseObject = dn.parse('');
this.baseObject = dn.parse('')
}
this.scope = options.scope || 'base';
this.derefAliases = options.derefAliases || Protocol.NEVER_DEREF_ALIASES;
this.sizeLimit = options.sizeLimit || 0;
this.timeLimit = options.timeLimit || 0;
this.typesOnly = options.typesOnly || false;
this.filter = options.filter || null;
this.attributes = options.attributes ? options.attributes.slice(0) : [];
this.scope = options.scope || 'base'
this.derefAliases = options.derefAliases || Protocol.NEVER_DEREF_ALIASES
this.sizeLimit = options.sizeLimit || 0
this.timeLimit = options.timeLimit || 0
this.typesOnly = options.typesOnly || false
this.filter = options.filter || null
this.attributes = options.attributes ? options.attributes.slice(0) : []
}
util.inherits(SearchRequest, LDAPMessage);
util.inherits(SearchRequest, LDAPMessage)
Object.defineProperties(SearchRequest.prototype, {
type: {
get: function getType() { return 'SearchRequest'; },
get: function getType () { return 'SearchRequest' },
configurable: false
},
_dn: {
get: function getDN() { return this.baseObject; },
get: function getDN () { return this.baseObject },
configurable: false
},
scope: {
get: function getScope() {
get: function getScope () {
switch (this._scope) {
case Protocol.SCOPE_BASE_OBJECT: return 'base';
case Protocol.SCOPE_ONE_LEVEL: return 'one';
case Protocol.SCOPE_SUBTREE: return 'sub';
default:
throw new Error(this._scope + ' is an invalid search scope');
case Protocol.SCOPE_BASE_OBJECT: return 'base'
case Protocol.SCOPE_ONE_LEVEL: return 'one'
case Protocol.SCOPE_SUBTREE: return 'sub'
default:
throw new Error(this._scope + ' is an invalid search scope')
}
},
set: function setScope(val) {
set: function setScope (val) {
if (typeof (val) === 'string') {
switch (val) {
case 'base':
this._scope = Protocol.SCOPE_BASE_OBJECT;
break;
case 'one':
this._scope = Protocol.SCOPE_ONE_LEVEL;
break;
case 'sub':
this._scope = Protocol.SCOPE_SUBTREE;
break;
default:
throw new Error(val + ' is an invalid search scope');
case 'base':
this._scope = Protocol.SCOPE_BASE_OBJECT
break
case 'one':
this._scope = Protocol.SCOPE_ONE_LEVEL
break
case 'sub':
this._scope = Protocol.SCOPE_SUBTREE
break
default:
throw new Error(val + ' is an invalid search scope')
}
} else {
this._scope = val;
this._scope = val
}
},
configurable: false
}
});
})
SearchRequest.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
this.baseObject = ber.readString();
this.scope = ber.readEnumeration();
this.derefAliases = ber.readEnumeration();
this.sizeLimit = ber.readInt();
this.timeLimit = ber.readInt();
this.typesOnly = ber.readBoolean();
this.baseObject = ber.readString()
this.scope = ber.readEnumeration()
this.derefAliases = ber.readEnumeration()
this.sizeLimit = ber.readInt()
this.timeLimit = ber.readInt()
this.typesOnly = ber.readBoolean()
this.filter = filters.parse(ber);
this.filter = filters.parse(ber)
// look for attributes
if (ber.peek() === 0x30) {
ber.readSequence();
var end = ber.offset + ber.length;
while (ber.offset < end)
this.attributes.push(ber.readString().toLowerCase());
ber.readSequence()
var end = ber.offset + ber.length
while (ber.offset < end) { this.attributes.push(ber.readString().toLowerCase()) }
}
return true;
};
return true
}
SearchRequest.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
ber.writeString(this.baseObject.toString());
ber.writeEnumeration(this._scope);
ber.writeEnumeration(this.derefAliases);
ber.writeInt(this.sizeLimit);
ber.writeInt(this.timeLimit);
ber.writeBoolean(this.typesOnly);
// Format only with commas, since that is what RFC 4514 mandates.
// There's a gotcha here: even though it's called baseObject,
// it can be a string or a DN object.
var formattedDN = dn.DN.isDN(this.baseObject)
? this.baseObject.format({ skipSpace: true })
: this.baseObject.toString()
ber.writeString(formattedDN)
ber.writeEnumeration(this._scope)
ber.writeEnumeration(this.derefAliases)
ber.writeInt(this.sizeLimit)
ber.writeInt(this.timeLimit)
ber.writeBoolean(this.typesOnly)
var f = this.filter || new filters.PresenceFilter({attribute: 'objectclass'});
ber = f.toBer(ber);
var f = this.filter || new filters.PresenceFilter({ attribute: 'objectclass' })
ber = f.toBer(ber)
ber.startSequence(Ber.Sequence | Ber.Constructor);
ber.startSequence(Ber.Sequence | Ber.Constructor)
if (this.attributes && this.attributes.length) {
this.attributes.forEach(function (a) {
ber.writeString(a);
});
ber.writeString(a)
})
}
ber.endSequence();
ber.endSequence()
return ber;
};
return ber
}
SearchRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
j.baseObject = this.baseObject;
j.scope = this.scope;
j.derefAliases = this.derefAliases;
j.sizeLimit = this.sizeLimit;
j.timeLimit = this.timeLimit;
j.typesOnly = this.typesOnly;
j.filter = this.filter.toString();
j.attributes = this.attributes;
j.baseObject = this.baseObject
j.scope = this.scope
j.derefAliases = this.derefAliases
j.sizeLimit = this.sizeLimit
j.timeLimit = this.timeLimit
j.typesOnly = this.typesOnly
j.filter = this.filter.toString()
j.attributes = this.attributes
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = SearchRequest;
module.exports = SearchRequest

View File

@ -1,32 +1,31 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPResult = require('./result');
var SearchEntry = require('./search_entry');
var SearchReference = require('./search_reference');
var LDAPResult = require('./result')
var SearchEntry = require('./search_entry')
var SearchReference = require('./search_reference')
var dtrace = require('../dtrace');
var parseDN = require('../dn').parse;
var parseURL = require('../url').parse;
var Protocol = require('../protocol');
var dtrace = require('../dtrace')
var parseDN = require('../dn').parse
var parseURL = require('../url').parse
var Protocol = require('../protocol')
/// --- API
///--- API
function SearchResponse (options) {
options = options || {}
assert.object(options)
function SearchResponse(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REP_SEARCH
LDAPResult.call(this, options)
options.protocolOp = Protocol.LDAP_REP_SEARCH;
LDAPResult.call(this, options);
this.attributes = options.attributes ? options.attributes.slice() : [];
this.notAttributes = [];
this.sentEntries = 0;
this.attributes = options.attributes ? options.attributes.slice() : []
this.notAttributes = []
this.sentEntries = 0
}
util.inherits(SearchResponse, LDAPResult);
util.inherits(SearchResponse, LDAPResult)
/**
* Allows you to send a SearchEntry back to the client.
@ -36,61 +35,54 @@ util.inherits(SearchResponse, LDAPResult);
* Defaults to 'false'.
*/
SearchResponse.prototype.send = function (entry, nofiltering) {
if (!entry || typeof (entry) !== 'object')
throw new TypeError('entry (SearchEntry) required');
if (nofiltering === undefined)
nofiltering = false;
if (typeof (nofiltering) !== 'boolean')
throw new TypeError('noFiltering must be a boolean');
if (!entry || typeof (entry) !== 'object') { throw new TypeError('entry (SearchEntry) required') }
if (nofiltering === undefined) { nofiltering = false }
if (typeof (nofiltering) !== 'boolean') { throw new TypeError('noFiltering must be a boolean') }
var self = this;
var self = this
if (entry instanceof SearchEntry || entry instanceof SearchReference) {
if (!entry.messageID)
entry.messageID = this.messageID;
if (entry.messageID !== this.messageID)
throw new Error('SearchEntry messageID mismatch');
if (!entry.messageID) { entry.messageID = this.messageID }
if (entry.messageID !== this.messageID) { throw new Error('SearchEntry messageID mismatch') }
} else {
if (!entry.attributes)
throw new Error('entry.attributes required');
if (!entry.attributes) { throw new Error('entry.attributes required') }
var savedAttrs = {};
var all = (self.attributes.indexOf('*') !== -1);
var savedAttrs = {}
var all = (self.attributes.indexOf('*') !== -1)
Object.keys(entry.attributes).forEach(function (a) {
var _a = a.toLowerCase();
var _a = a.toLowerCase()
if (!nofiltering && _a.length && _a[0] === '_') {
savedAttrs[a] = entry.attributes[a];
delete entry.attributes[a];
savedAttrs[a] = entry.attributes[a]
delete entry.attributes[a]
} else if (!nofiltering && self.notAttributes.indexOf(_a) !== -1) {
savedAttrs[a] = entry.attributes[a];
delete entry.attributes[a];
savedAttrs[a] = entry.attributes[a]
delete entry.attributes[a]
} else if (all) {
return;
} else if (self.attributes.length && self.attributes.indexOf(_a) === -1) {
savedAttrs[a] = entry.attributes[a];
delete entry.attributes[a];
}
});
var save = entry;
} else if (self.attributes.length && self.attributes.indexOf(_a) === -1) {
savedAttrs[a] = entry.attributes[a]
delete entry.attributes[a]
}
})
var save = entry
entry = new SearchEntry({
objectName: typeof (save.dn) === 'string' ? parseDN(save.dn) : save.dn,
messageID: self.messageID,
log: self.log
});
entry.fromObject(save);
})
entry.fromObject(save)
}
try {
if (this.log.debug())
this.log.debug('%s: sending: %j', this.connection.ldap.id, entry.json);
if (this.log.debug) { this.log.debug('%s: sending: %j', this.connection.ldap.id, entry.json) }
this.connection.write(entry.toBer());
this.sentEntries++;
this.connection.write(entry.toBer())
this.sentEntries++
if (self._dtraceOp && self._dtraceId) {
dtrace.fire('server-search-entry', function () {
var c = self.connection || {ldap: {}};
var c = self.connection || { ldap: {} }
return [
self._dtraceId || 0,
(c.remoteAddress || ''),
@ -98,54 +90,49 @@ SearchResponse.prototype.send = function (entry, nofiltering) {
(self.requestDN ? self.requestDN.toString() : ''),
entry.objectName.toString(),
entry.attributes.length
];
});
]
})
}
// Restore attributes
Object.keys(savedAttrs || {}).forEach(function (k) {
save.attributes[k] = savedAttrs[k];
});
save.attributes[k] = savedAttrs[k]
})
} catch (e) {
this.log.warn(e, '%s failure to write message %j',
this.connection.ldap.id, this.json);
this.connection.ldap.id, this.json)
}
};
}
SearchResponse.prototype.createSearchEntry = function (object) {
assert.object(object);
assert.object(object)
var entry = new SearchEntry({
messageID: this.messageID,
log: this.log,
objectName: object.objectName || object.dn
});
entry.fromObject((object.attributes || object));
return entry;
};
})
entry.fromObject((object.attributes || object))
return entry
}
SearchResponse.prototype.createSearchReference = function (uris) {
if (!uris)
throw new TypeError('uris ([string]) required');
if (!uris) { throw new TypeError('uris ([string]) required') }
if (!Array.isArray(uris))
uris = [uris];
if (!Array.isArray(uris)) { uris = [uris] }
for (var i = 0; i < uris.length; i++) {
if (typeof (uris[i]) == 'string')
uris[i] = parseURL(uris[i]);
if (typeof (uris[i]) === 'string') { uris[i] = parseURL(uris[i]) }
}
var self = this;
var self = this
return new SearchReference({
messageID: self.messageID,
log: self.log,
uris: uris
});
};
})
}
/// --- Exports
///--- Exports
module.exports = SearchResponse;
module.exports = SearchResponse

View File

@ -1,65 +1,62 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var LDAPMessage = require('./message');
var dn = require('../dn');
var Protocol = require('../protocol');
var LDAPMessage = require('./message')
var dn = require('../dn')
var Protocol = require('../protocol')
/// --- Globals
///--- Globals
var DN = dn.DN
var RDN = dn.RDN
var DN = dn.DN;
var RDN = dn.RDN;
/// --- API
function UnbindRequest (options) {
options = options || {}
assert.object(options)
///--- API
function UnbindRequest(options) {
options = options || {};
assert.object(options);
options.protocolOp = Protocol.LDAP_REQ_UNBIND;
LDAPMessage.call(this, options);
options.protocolOp = Protocol.LDAP_REQ_UNBIND
LDAPMessage.call(this, options)
}
util.inherits(UnbindRequest, LDAPMessage);
util.inherits(UnbindRequest, LDAPMessage)
Object.defineProperties(UnbindRequest.prototype, {
type: {
get: function getType() { return 'UnbindRequest'; },
get: function getType () { return 'UnbindRequest' },
configurable: false
},
_dn: {
get: function getDN() {
get: function getDN () {
if (this.connection) {
return this.connection.ldap.bindDN;
return this.connection.ldap.bindDN
} else {
return new DN([new RDN({cn: 'anonymous'})]);
return new DN([new RDN({ cn: 'anonymous' })])
}
},
configurable: false
}
});
})
UnbindRequest.prototype._parse = function (ber) {
assert.ok(ber);
assert.ok(ber)
return true;
};
return true
}
UnbindRequest.prototype._toBer = function (ber) {
assert.ok(ber);
assert.ok(ber)
return ber;
};
return ber
}
UnbindRequest.prototype._json = function (j) {
assert.ok(j);
assert.ok(j)
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = UnbindRequest;
module.exports = UnbindRequest

View File

@ -1,33 +1,32 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var assert = require('assert-plus');
var util = require('util');
var assert = require('assert-plus')
var util = require('util')
var dtrace = require('../dtrace');
var dtrace = require('../dtrace')
var LDAPMessage = require('./result');
var Protocol = require('../protocol');
var LDAPMessage = require('./result')
// var Protocol = require('../protocol')
///--- API
/// --- API
// Ok, so there's really no such thing as an unbind 'response', but to make
// the framework not suck, I just made this up, and have it stubbed so it's
// not such a one-off.
function UnbindResponse(options) {
options = options || {};
assert.object(options);
function UnbindResponse (options) {
options = options || {}
assert.object(options)
options.protocolOp = 0;
LDAPMessage.call(this, options);
options.protocolOp = 0
LDAPMessage.call(this, options)
}
util.inherits(UnbindResponse, LDAPMessage);
util.inherits(UnbindResponse, LDAPMessage)
Object.defineProperties(UnbindResponse.prototype, {
type: {
get: function getType() { return 'UnbindResponse'; },
get: function getType () { return 'UnbindResponse' },
configurable: false
}
});
})
/**
* Special override that just ends the connection, if present.
@ -35,16 +34,16 @@ Object.defineProperties(UnbindResponse.prototype, {
* @param {Number} status completely ignored.
*/
UnbindResponse.prototype.end = function (status) {
assert.ok(this.connection);
assert.ok(this.connection)
this.log.trace('%s: unbinding!', this.connection.ldap.id);
this.log.trace('%s: unbinding!', this.connection.ldap.id)
this.connection.end();
this.connection.end()
var self = this;
var self = this
if (self._dtraceOp && self._dtraceId) {
dtrace.fire('server-' + self._dtraceOp + '-done', function () {
var c = self.connection || {ldap: {}};
var c = self.connection || { ldap: {} }
return [
self._dtraceId || 0,
(c.remoteAddress || ''),
@ -52,16 +51,15 @@ UnbindResponse.prototype.end = function (status) {
(self.requestDN ? self.requestDN.toString() : ''),
0,
''
];
});
]
})
}
};
}
UnbindResponse.prototype._json = function (j) {
return j;
};
return j
}
/// --- Exports
///--- Exports
module.exports = UnbindResponse;
module.exports = UnbindResponse

View File

@ -1,123 +1,109 @@
///--- Globals
/// --- Globals
var parseDN = require('./dn').parse;
// var parseDN = require('./dn').parse
var EntryChangeNotificationControl =
require('./controls').EntryChangeNotificationControl;
require('./controls').EntryChangeNotificationControl
///--- API
/// --- API
// Cache used to store connected persistent search clients
function PersistentSearch() {
this.clientList = [];
function PersistentSearch () {
this.clientList = []
}
PersistentSearch.prototype.addClient = function (req, res, callback) {
if (typeof (req) !== 'object')
throw new TypeError('req must be an object');
if (typeof (res) !== 'object')
throw new TypeError('res must be an object');
if (callback && typeof (callback) !== 'function')
throw new TypeError('callback must be a function');
if (typeof (req) !== 'object') { throw new TypeError('req must be an object') }
if (typeof (res) !== 'object') { throw new TypeError('res must be an object') }
if (callback && typeof (callback) !== 'function') { throw new TypeError('callback must be a function') }
var log = req.log;
var log = req.log
var client = {};
client.req = req;
client.res = res;
var client = {}
client.req = req
client.res = res
log.debug('%s storing client', req.logId);
log.debug('%s storing client', req.logId)
this.clientList.push(client);
this.clientList.push(client)
log.debug('%s stored client', req.logId);
log.debug('%s stored client', req.logId)
log.debug('%s total number of clients %s',
req.logId, this.clientList.length);
if (callback)
callback(client);
};
req.logId, this.clientList.length)
if (callback) { callback(client) }
}
PersistentSearch.prototype.removeClient = function (req, res, callback) {
if (typeof (req) !== 'object')
throw new TypeError('req must be an object');
if (typeof (res) !== 'object')
throw new TypeError('res must be an object');
if (callback && typeof (callback) !== 'function')
throw new TypeError('callback must be a function');
if (typeof (req) !== 'object') { throw new TypeError('req must be an object') }
if (typeof (res) !== 'object') { throw new TypeError('res must be an object') }
if (callback && typeof (callback) !== 'function') { throw new TypeError('callback must be a function') }
var log = req.log;
log.debug('%s removing client', req.logId);
var client = {};
client.req = req;
client.res = res;
var log = req.log
log.debug('%s removing client', req.logId)
var client = {}
client.req = req
client.res = res
// remove the client if it exists
this.clientList.forEach(function (element, index, array) {
if (element.req === client.req) {
log.debug('%s removing client from list', req.logId);
array.splice(index, 1);
log.debug('%s removing client from list', req.logId)
array.splice(index, 1)
}
});
})
log.debug('%s number of persistent search clients %s',
req.logId, this.clientList.length);
if (callback)
callback(client);
};
req.logId, this.clientList.length)
if (callback) { callback(client) }
}
function getOperationType(requestType) {
function getOperationType (requestType) {
switch (requestType) {
case 'AddRequest':
case 'add':
return 1;
return 1
case 'DeleteRequest':
case 'delete':
return 2;
return 2
case 'ModifyRequest':
case 'modify':
return 4;
return 4
case 'ModifyDNRequest':
case 'modrdn':
return 8;
return 8
default:
throw new TypeError('requestType %s, is an invalid request type',
requestType);
requestType)
}
}
function getEntryChangeNotificationControl(req, obj, callback) {
function getEntryChangeNotificationControl (req, obj, callback) {
// if we want to return a ECNC
if (req.persistentSearch.value.returnECs) {
var attrs = obj.attributes;
var value = {};
value.changeType = getOperationType(attrs.changetype);
var attrs = obj.attributes
var value = {}
value.changeType = getOperationType(attrs.changetype)
// if it's a modDN request, fill in the previous DN
if (value.changeType === 8 && attrs.previousDN) {
value.previousDN = attrs.previousDN;
value.previousDN = attrs.previousDN
}
value.changeNumber = attrs.changenumber;
return new EntryChangeNotificationControl({ value: value });
value.changeNumber = attrs.changenumber
return new EntryChangeNotificationControl({ value: value })
} else {
return false;
return false
}
}
function checkChangeType(req, requestType) {
function checkChangeType (req, requestType) {
return (req.persistentSearch.value.changeTypes &
getOperationType(requestType));
getOperationType(requestType))
}
///--- Exports
/// --- Exports
module.exports = {
PersistentSearchCache: PersistentSearch,
checkChangeType: checkChangeType,
getEntryChangeNotificationControl: getEntryChangeNotificationControl
};
}

View File

@ -1,6 +1,5 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
module.exports = {
// Misc
@ -51,4 +50,4 @@ module.exports = {
LDAP_REP_MODRDN: 0x6d,
LDAP_REP_COMPARE: 0x6f,
LDAP_REP_EXTENSION: 0x78
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +1,72 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var querystring = require('querystring');
var url = require('url');
var util = require('util');
var dn = require('./dn');
var filter = require('./filters/index');
'use strict'
const querystring = require('querystring')
const url = require('url')
const dn = require('./dn')
const filter = require('./filters/')
module.exports = {
parse: function (urlStr, parseDN) {
var u = url.parse(urlStr);
if (!u.protocol || !(u.protocol === 'ldap:' || u.protocol === 'ldaps:'))
throw new TypeError(urlStr + ' is an invalid LDAP url (protocol)');
let parsedURL
try {
parsedURL = new url.URL(urlStr)
} catch (error) {
throw new TypeError(urlStr + ' is an invalid LDAP url (scope)')
}
u.secure = (u.protocol === 'ldaps:');
if (!parsedURL.protocol || !(parsedURL.protocol === 'ldap:' || parsedURL.protocol === 'ldaps:')) { throw new TypeError(urlStr + ' is an invalid LDAP url (protocol)') }
if (!u.hostname)
u.hostname = 'localhost';
const u = {
protocol: parsedURL.protocol,
hostname: parsedURL.hostname,
port: parsedURL.port,
pathname: parsedURL.pathname,
search: parsedURL.search,
href: parsedURL.href
}
u.secure = (u.protocol === 'ldaps:')
if (!u.hostname) { u.hostname = 'localhost' }
if (!u.port) {
u.port = (u.secure ? 636 : 389);
u.port = (u.secure ? 636 : 389)
} else {
u.port = parseInt(u.port, 10);
u.port = parseInt(u.port, 10)
}
if (u.pathname) {
u.pathname = querystring.unescape(u.pathname.substr(1));
u.DN = parseDN ? dn.parse(u.pathname) : u.pathname;
u.pathname = querystring.unescape(u.pathname.substr(1))
u.DN = parseDN ? dn.parse(u.pathname) : u.pathname
}
if (u.search) {
u.attributes = [];
var tmp = u.search.substr(1).split('?');
u.attributes = []
var tmp = u.search.substr(1).split('?')
if (tmp && tmp.length) {
if (tmp[0]) {
tmp[0].split(',').forEach(function (a) {
u.attributes.push(querystring.unescape(a.trim()));
});
u.attributes.push(querystring.unescape(a.trim()))
})
}
}
if (tmp[1]) {
if (tmp[1] !== 'base' && tmp[1] !== 'one' && tmp[1] !== 'sub')
throw new TypeError(urlStr + ' is an invalid LDAP url (scope)');
u.scope = tmp[1];
if (tmp[1] !== 'base' && tmp[1] !== 'one' && tmp[1] !== 'sub') { throw new TypeError(urlStr + ' is an invalid LDAP url (scope)') }
u.scope = tmp[1]
}
if (tmp[2]) {
u.filter = querystring.unescape(tmp[2]);
u.filter = querystring.unescape(tmp[2])
}
if (tmp[3]) {
u.extensions = querystring.unescape(tmp[3]);
u.extensions = querystring.unescape(tmp[3])
}
if (!u.scope)
u.scope = 'base';
if (!u.filter)
u.filter = filter.parseString('(objectclass=*)');
else
u.filter = filter.parseString(u.filter);
if (!u.scope) { u.scope = 'base' }
if (!u.filter) { u.filter = filter.parseString('(objectclass=*)') } else { u.filter = filter.parseString(u.filter) }
}
return u;
return u
}
};
}

View File

@ -1,55 +1,53 @@
{
"author": "Mark Cavage <mcavage@gmail.com>",
"contributors": [
"Craig Baker",
"Austin King <shout@ozten.com>",
"Mathieu Lecarme <mathieu@garambrogne.net>>",
"Trent Mick <trentm@gmail.com>",
"Yunong Xiao <yunong@joyent.com>",
"Denis Vuyka <denis.vuyka@gmail.com>",
"Pedro Palazón <kusorbox@gmail.com>",
"Patrick Mooney <patrick.f.mooney@gmail.com>",
"Matt Simerson <matt@tnpi.net>"
],
"originalAuthor": "Mark Cavage <mcavage@gmail.com>",
"name": "ldapjs",
"homepage": "http://ldapjs.org",
"description": "LDAP client and server APIs",
"version": "1.0.2",
"version": "2.0.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/mcavage/node-ldapjs.git"
"url": "git://github.com/ldapjs/node-ldapjs.git"
},
"main": "lib/index.js",
"directories": {
"bin": "./bin",
"lib": "./lib"
},
"engines": {
"node": ">=0.10"
"node": ">=10.13.0"
},
"dependencies": {
"asn1": "0.2.3",
"abstract-logging": "^1.0.0",
"asn1": "^0.2.4",
"assert-plus": "^1.0.0",
"bunyan": "^1.8.3",
"dashdash": "^1.14.0",
"backoff": "^2.5.0",
"ldap-filter": "0.2.2",
"ldap-filter": "^0.3.3",
"once": "^1.4.0",
"vasync": "^1.6.4",
"vasync": "^2.2.0",
"verror": "^1.8.1"
},
"optionalDependencies": {
"dtrace-provider": "~0.8"
},
"devDependencies": {
"node-uuid": "^1.4.7",
"faucet": "0.0.1",
"istanbul": "^0.4.5",
"tape": "^4.6.2"
"get-port": "^5.1.1",
"husky": "^3.0.4",
"snazzy": "^8.0.0",
"standard": "^14.0.2",
"tap": "14.10.1",
"uuid": "^3.3.3"
},
"scripts": {
"report": "./node_modules/.bin/istanbul report html && open ./coverage/lcov-report/index.html",
"test": "./node_modules/.bin/istanbul cover --print none test/test.js | ./node_modules/.bin/faucet"
"test": "tap --no-cov",
"test:ci": "tap --coverage-report=lcovonly",
"test:cov": "tap",
"test:cov:html": "tap --coverage-report=html",
"test:watch": "tap -n -w --no-coverage-report",
"test:integration": "tap --no-cov 'test-integration/**/*.test.js'",
"test:integration:local": "docker-compose up -d && npm run test:integration && docker-compose down",
"lint": "standard | snazzy",
"lint:ci": "standard"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint && npm run test"
}
}
}

Some files were not shown because too many files have changed in this diff Show More