From d8df23fa06e0b92379c7fedcb44b3e657837bf10 Mon Sep 17 00:00:00 2001
From: a-schild <andre@schild.ws>
Date: Thu, 7 Mar 2019 17:23:58 +0100
Subject: [PATCH] - Upgraded to ldapjs 1.0.2 - substring queries are now case
 insensitive   Was an issue in in nextcloud group sharing for example

---
 CHANGELOG.md |  7 +++++++
 README.md    |  2 +-
 ctldap.js    | 43 +++++++++++++++++++++++++++++++++++++++----
 package.json | 14 +++++++++-----
 4 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 257155d..bd38d82 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Changelog
 
+### 2.1
+- Upgraded to ldapjs 1.0.2
+- Fixed wrong street mapping
+- Consistent logging
+- substring queries are now case insensitive
+  Was an issue in in nextcloud group sharing for example
+
 ### 2.0
 - adapted to built-in ChurchTools ctldap API
 
diff --git a/README.md b/README.md
index 2224a89..129a2b9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# LDAP Wrapper for ChurchTools v2.0
+# LDAP Wrapper for ChurchTools v2.1
 
 This software acts as an LDAP server for ChurchTools >= 3.25.0
 
diff --git a/ctldap.js b/ctldap.js
index 3def6dd..80bb7db 100644
--- a/ctldap.js
+++ b/ctldap.js
@@ -1,6 +1,7 @@
-// ChurchTools LDAP-Wrapper 2.0
+// ChurchTools LDAP-Wrapper 2.1
 // This tool requires a node.js-Server and ChurchTools >= 3.25.0
 // (c) 2017 Michael Lux
+// (c) 2019 André Schild
 // License: GNU/GPL v3.0
 
 var ldap = require('ldapjs');
@@ -8,11 +9,14 @@ var fs = require('fs');
 var ini = require('ini');
 var rp = require('request-promise');
 var ldapEsc = require('ldap-escape');
+var parseDN = require('ldapjs').parseDN;
 var extend = require('extend');
 var Promise = require("bluebird");
 var path = require('path');
 var bcrypt = require('bcrypt');
 
+var helpers = require('ldap-filter/lib/helpers');
+
 var config = ini.parse(fs.readFileSync(path.resolve(__dirname, 'ctldap.config'), 'utf-8'));
 if (config.debug) {
   console.log("Debug mode enabled, expect lots of output!");
@@ -285,6 +289,7 @@ function requestUsers (req, res, next) {
             uid: cn,
             nsuniqueid: "u0",
             givenname: "LDAP Administrator",
+            objectclass: ['CTPerson'],
           }
         });
       }
@@ -373,7 +378,7 @@ function sendUsers (req, res, next) {
   var strDn = req.dn.toString();
   req.usersPromise.then(function (users) {
     users.forEach(function (u) {
-      if ((req.checkAll || strDn === u.dn) && (req.filter.matches(u.attributes))) {
+      if ((req.checkAll || parseDN(strDn).equals(parseDN(u.dn))) && (req.filter.matches(u.attributes))) {
         if (config.debug) {
           console.log("[DEBUG] MatchUser: " + u.dn);
         }
@@ -390,7 +395,7 @@ function sendUsers (req, res, next) {
 }
 
 /**
- * Evaluetes req.groupsPromise and sends matching elements to the client.
+ * Evaluates req.groupsPromise and sends matching elements to the client.
  * @param {object} req - Request object
  * @param {object} res - Response object
  * @param {function} next - Next handler function of filter chain
@@ -399,7 +404,7 @@ function sendGroups (req, res, next) {
   var strDn = req.dn.toString();
   req.groupsPromise.then(function (groups) {
     groups.forEach(function (g) {
-      if ((req.checkAll || strDn === g.dn) && (req.filter.matches(g.attributes))) {
+      if ((req.checkAll || parseDN(strDn).equals(parseDN(g.dn))) && (req.filter.matches(g.attributes))) {
         if (config.debug) {
           console.log("[DEBUG] MatchGroup: " + g.dn);
         }
@@ -537,6 +542,36 @@ server.search('', function (req, res, next) {
   res.end();
 }, endSuccess);
 
+
+function escapeRegExp(str) {
+  /* JSSTYLED */
+  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
+}
+
+/** Case insensitive search on substring filters */
+ldap.SubstringFilter.prototype.matches = function (target, strictAttrCase) {
+  var tv = helpers.getAttrValue(target, this.attribute, strictAttrCase);
+  if (tv !== undefined && tv !== null) {
+    var re = '';
+
+    if (this.initial)
+      re += '^' + escapeRegExp(this.initial) + '.*';
+    this.any.forEach(function (s) {
+      re += escapeRegExp(s) + '.*';
+    });
+    if (this.final)
+      re += escapeRegExp(this.final) + '$';
+
+    var matcher = new RegExp(re, 'i');
+    return helpers.testValues(function (v) {
+      return matcher.test(v);
+    }, tv);
+  }
+
+  return false;
+};
+
+
 // Start LDAP server
 server.listen(parseInt(config.ldap_port), function () {
   console.log('ChurchTools-LDAP-Wrapper listening @ %s', server.url);
diff --git a/package.json b/package.json
index 6628630..c7a9b99 100644
--- a/package.json
+++ b/package.json
@@ -2,17 +2,21 @@
   "name": "ctldap",
   "license": "GPL-3.0",
   "description": "LDAP Wrapper for ChurchTools",
-  "version": "1.0.1",
+  "version": "2.1.0",
   "private": true,
   "dependencies": {
-    "bcrypt": "^2.0.1",
+    "bcrypt": "^3.0.4",
     "bluebird": "^3.5.0",
     "extend": "^3.0.1",
     "ini": "^1.1.0",
-    "ldap-escape": "^1.1.4",
-    "ldapjs": "^0.7.0",
+    "ldap-escape": "^1.1.5",
+    "ldapjs": "^1.0.2",
     "request": "^2.81.0",
     "request-promise": "^4.2.1"
   },
-  "devDependencies": {}
+  "devDependencies": {},
+    "scripts": {
+        "start": "node ctldap.js"
+    }
+
 }