diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..33e95a2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,35 @@ +env: + - CABALVER=1.18 GHCVER=7.6.3 + - CABALVER=1.18 GHCVER=7.8.4 + - CABALVER=1.22 GHCVER=7.10.1 + +before_install: + - travis_retry sudo add-apt-repository -y ppa:hvr/ghc + - travis_retry sudo apt-get update + - travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER npm + - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH + +install: + - cabal --version + - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" + - travis_retry cabal update + - cabal install --only-dependencies --enable-tests --enable-benchmarks + - npm install ldapjs + +script: + - cabal configure --enable-tests -v2 + - cabal build + - cabal test + - | + if [ $GHCVER = "7.10.1" ]; then + cabal check + fi + - cabal sdist + - export SRC_TGZ=$(cabal info . | awk '{print $2 ".tar.gz";exit}') ; + cd dist/; + if [ -f "$SRC_TGZ" ]; then + cabal install --force-reinstalls "$SRC_TGZ"; + else + echo "expected '$SRC_TGZ' not found"; + exit 1; + fi diff --git a/README.markdown b/README.markdown index dded339..ff90d3e 100644 --- a/README.markdown +++ b/README.markdown @@ -2,6 +2,7 @@ ldap-client =========== +[![Build Status](https://travis-ci.org/supki/ldap-client.svg?branch=master)](https://travis-ci.org/supki/ldap-client) This library implements (the parts of) [RFC 4511][rfc4511] @@ -22,24 +23,8 @@ IntermediateResponse Message | 4.13 | ✘ StartTLS Operation | 4.14 | ✔† LDAP over TLS | - | ✔ -\*: approximate and extensible matches are untested, so probably do not work -†: only serves as an example of Extended Operation, meaning that it does not change -connection's state on success, so it's useless for all practical purposes. -In other words, use LDAP over TLS instead. - -``` -% git grep '\bString\b' | wc -l -2 -``` - -Testing -------- - -```shell -% sudo apt-get install npm -% npm install ldapjs -% cabal test -``` +\* Approximate and extensible matches are untested, so probably do not work +† Only serves as an example of Extended Operation. It's useless for all practical purposes as it does not actually enable TLS. In other words, use LDAP over TLS instead. [rfc4511]: https://tools.ietf.org/html/rfc4511 [LDAP]: https://hackage.haskell.org/package/LDAP diff --git a/ldap-client.cabal b/ldap-client.cabal index 05e1a7d..eeac1cd 100644 --- a/ldap-client.cabal +++ b/ldap-client.cabal @@ -33,6 +33,7 @@ library Ldap.Client.Bind Ldap.Client.Compare Ldap.Client.Delete + Ldap.Client.Extended Ldap.Client.Internal Ldap.Client.Modify Ldap.Client.Search @@ -40,7 +41,7 @@ library asn1-encoding >= 0.9 , asn1-types >= 0.3 , async - , base >= 4.7 && < 5 + , base >= 4.6 && < 5 , bytestring , connection >= 0.2 , containers @@ -59,17 +60,18 @@ test-suite spec main-is: Spec.hs other-modules: - Ldap.Client Ldap.Client.AddSpec Ldap.Client.BindSpec Ldap.Client.CompareSpec Ldap.Client.DeleteSpec - Ldap.Client.InternalSpec + Ldap.Client.ExtendedSpec Ldap.Client.ModifySpec Ldap.Client.SearchSpec SpecHelper build-depends: - base >= 4.7 && < 5 + base >= 4.6 && < 5 + , bytestring , hspec , ldap-client , process + , semigroups diff --git a/src/Ldap/Asn1/FromAsn1.hs b/src/Ldap/Asn1/FromAsn1.hs index 34755fd..bd03ed2 100644 --- a/src/Ldap/Asn1/FromAsn1.hs +++ b/src/Ldap/Asn1/FromAsn1.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} module Ldap.Asn1.FromAsn1 ( FromAsn1(..) , Parser @@ -6,7 +7,11 @@ module Ldap.Asn1.FromAsn1 , next ) where +#if __GLASGOW_HASKELL__ >= 710 import Control.Applicative (Alternative(..), liftA2, optional) +#else +import Control.Applicative (Applicative(..), Alternative(..), liftA2, optional) +#endif import Control.Monad (MonadPlus(..), (>=>), guard) import Data.ASN1.Types (ASN1) import qualified Data.ASN1.Types as Asn1 diff --git a/src/Ldap/Client.hs b/src/Ldap/Client.hs index 1634b84..c449551 100644 --- a/src/Ldap/Client.hs +++ b/src/Ldap/Client.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE NamedFieldPuns #-} @@ -44,6 +45,9 @@ module Ldap.Client , waitSTM ) where +#if __GLASGOW_HASKELL__ < 710 +import Control.Applicative ((<$>)) +#endif import qualified Control.Concurrent.Async as Async import Control.Concurrent.STM (atomically) import Control.Concurrent.STM.TMVar (putTMVar) diff --git a/src/Ldap/Client/Internal.hs b/src/Ldap/Client/Internal.hs index 6a0a821..2cd9a44 100644 --- a/src/Ldap/Client/Internal.hs +++ b/src/Ldap/Client/Internal.hs @@ -32,6 +32,7 @@ import Control.Exception (Exception, throwIO) import Data.ByteString (ByteString) import Data.List.NonEmpty (NonEmpty) import Data.Text (Text) +import Data.Typeable (Typeable) import Network (PortNumber) import qualified Ldap.Asn1.Type as Type @@ -71,7 +72,7 @@ newtype Password = Password ByteString data ResponseError = ResponseInvalid Request Response | ResponseErrorCode Request Type.ResultCode Dn Text - deriving (Show, Eq) + deriving (Show, Eq, Typeable) instance Exception ResponseError diff --git a/src/Ldap/Client/Search.hs b/src/Ldap/Client/Search.hs index e8c5009..4f756bb 100644 --- a/src/Ldap/Client/Search.hs +++ b/src/Ldap/Client/Search.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE NamedFieldPuns #-} module Ldap.Client.Search ( search @@ -21,7 +22,11 @@ import Data.Int (Int32) import Data.List.NonEmpty (NonEmpty((:|))) import qualified Data.List.NonEmpty as NonEmpty import Data.Maybe (mapMaybe) +#if __GLASGOW_HASKELL__ >= 710 import Data.Semigroup (Semigroup(..)) +#else +import Data.Semigroup (Semigroup(..), Monoid(..)) +#endif import qualified Ldap.Asn1.Type as Type import Ldap.Client.Internal diff --git a/test/Ldap/Client/AddSpec.hs b/test/Ldap/Client/AddSpec.hs index b71339c..42bb0a1 100644 --- a/test/Ldap/Client/AddSpec.hs +++ b/test/Ldap/Client/AddSpec.hs @@ -1,7 +1,7 @@ -{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} module Ldap.Client.AddSpec (spec) where +import qualified Data.List.NonEmpty as NonEmpty import Data.Monoid ((<>)) import Test.Hspec @@ -21,9 +21,9 @@ spec = do it "adds an entry" $ do res <- locally $ \l -> do Ldap.add l vulpix - [ (Attr "cn", ["vulpix"]) - , (Attr "evolution", ["0"]) - , (Attr "type", ["fire"]) + [ (Attr "cn", (NonEmpty.fromList ["vulpix"])) + , (Attr "evolution", (NonEmpty.fromList ["0"])) + , (Attr "type", (NonEmpty.fromList ["fire"])) ] res <- go l (Attr "cn" := "vulpix") dns res `shouldBe` [vulpix] diff --git a/test/Ldap/Client/DeleteSpec.hs b/test/Ldap/Client/DeleteSpec.hs index 424a8df..9141299 100644 --- a/test/Ldap/Client/DeleteSpec.hs +++ b/test/Ldap/Client/DeleteSpec.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} module Ldap.Client.DeleteSpec (spec) where diff --git a/test/Ldap/Client/SearchSpec.hs b/test/Ldap/Client/SearchSpec.hs index a644052..8a4eee6 100644 --- a/test/Ldap/Client/SearchSpec.hs +++ b/test/Ldap/Client/SearchSpec.hs @@ -1,7 +1,7 @@ -{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} module Ldap.Client.SearchSpec (spec) where +import qualified Data.List.NonEmpty as NonEmpty import Data.Monoid ((<>)) import Test.Hspec import Ldap.Client as Ldap @@ -70,17 +70,17 @@ spec = do it "‘and’ filter" $ do res <- locally $ \l -> do - res <- go l (And [ Attr "type" := "fire" - , Attr "evolution" := "1" - ]) + res <- go l (And (NonEmpty.fromList [ Attr "type" := "fire" + , Attr "evolution" := "1" + ])) dns res `shouldBe` [charmeleon] res `shouldBe` Right () it "‘or’ filter" $ do res <- locally $ \l -> do - res <- go l (Or [ Attr "type" := "fire" - , Attr "evolution" := "1" - ]) + res <- go l (Or (NonEmpty.fromList [ Attr "type" := "fire" + , Attr "evolution" := "1" + ])) dns res `shouldMatchList` [ ivysaur , charizard @@ -116,9 +116,9 @@ spec = do it "‘not’ filter" $ do res <- locally $ \l -> do - res <- go l (Not (Or [ Attr "type" := "fire" - , Attr "evolution" :>= "1" - ])) + res <- go l (Not (Or (NonEmpty.fromList [ Attr "type" := "fire" + , Attr "evolution" :>= "1" + ]))) dns res `shouldMatchList` [ bulbasaur , squirtle diff --git a/test/ldap.js b/test/ldap.js index 7752293..8cb0965 100755 --- a/test/ldap.js +++ b/test/ldap.js @@ -1,4 +1,4 @@ -#!/usr/bin/env nodejs +#!/usr/bin/env js var fs = require('fs'); var ldapjs = require('ldapjs'); @@ -183,6 +183,6 @@ server.compare('o=localhost', [], function(req, res, next) { return next(new ldapjs.NoSuchObjectError(req.dn.toString())); }); -server.listen(port, function() { +server.listen(port, '0.0.0.0', function() { console.log("ldaps://localhost:%d", port); });