git subrepo commit (merge) mailcow/src/mailcow-dockerized

subrepo: subdir:   "mailcow/src/mailcow-dockerized"
  merged:   "02ae5285"
upstream: origin:   "https://github.com/mailcow/mailcow-dockerized.git"
  branch:   "master"
  commit:   "649a5c01"
git-subrepo: version:  "0.4.3"
  origin:   "???"
  commit:   "???"
Change-Id: I870ad468fba026cc5abf3c5699ed1e12ff28b32b
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/AuthGuardFake.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/AuthGuardFake.php
new file mode 100644
index 0000000..4a69150
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/AuthGuardFake.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace LdapRecord\Testing;
+
+use LdapRecord\Auth\Guard;
+
+class AuthGuardFake extends Guard
+{
+    /**
+     * Always allow binding as configured user.
+     *
+     * @return bool
+     */
+    public function bindAsConfiguredUser()
+    {
+        return true;
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/ConnectionFake.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/ConnectionFake.php
new file mode 100644
index 0000000..0aa12a1
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/ConnectionFake.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace LdapRecord\Testing;
+
+use LdapRecord\Auth\Guard;
+use LdapRecord\Connection;
+use LdapRecord\Models\Model;
+
+class ConnectionFake extends Connection
+{
+    /**
+     * The underlying fake LDAP connection.
+     *
+     * @var LdapFake
+     */
+    protected $ldap;
+
+    /**
+     * Whether the fake is connected.
+     *
+     * @var bool
+     */
+    protected $connected = false;
+
+    /**
+     * Make a new fake LDAP connection instance.
+     *
+     * @param array  $config
+     * @param string $ldap
+     *
+     * @return static
+     */
+    public static function make(array $config = [], $ldap = LdapFake::class)
+    {
+        $connection = new static($config, new $ldap());
+
+        $connection->configure();
+
+        return $connection;
+    }
+
+    /**
+     * Set the user to authenticate as.
+     *
+     * @param Model|string $user
+     *
+     * @return $this
+     */
+    public function actingAs($user)
+    {
+        $this->ldap->shouldAuthenticateWith(
+            $user instanceof Model ? $user->getDn() : $user
+        );
+
+        return $this;
+    }
+
+    /**
+     * Set the connection to bypass bind attempts as the configured user.
+     *
+     * @return $this
+     */
+    public function shouldBeConnected()
+    {
+        $this->connected = true;
+
+        $this->authGuardResolver = function () {
+            return new AuthGuardFake($this->ldap, $this->configuration);
+        };
+
+        return $this;
+    }
+
+    /**
+     * Set the connection to attempt binding as the configured user.
+     *
+     * @return $this
+     */
+    public function shouldNotBeConnected()
+    {
+        $this->connected = false;
+
+        $this->authGuardResolver = function () {
+            return new Guard($this->ldap, $this->configuration);
+        };
+
+        return $this;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function isConnected()
+    {
+        return $this->connected ?: parent::isConnected();
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/DirectoryFake.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/DirectoryFake.php
new file mode 100644
index 0000000..70640af
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/DirectoryFake.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace LdapRecord\Testing;
+
+use LdapRecord\Container;
+
+class DirectoryFake
+{
+    /**
+     * Setup the fake connection.
+     *
+     * @param string|null $name
+     *
+     * @throws \LdapRecord\ContainerException
+     *
+     * @return ConnectionFake
+     */
+    public static function setup($name = null)
+    {
+        $connection = Container::getConnection($name);
+
+        $fake = static::makeConnectionFake(
+            $connection->getConfiguration()->all()
+        );
+
+        // Replace the connection with a fake.
+        Container::addConnection($fake, $name);
+
+        return $fake;
+    }
+
+    /**
+     * Reset the container.
+     *
+     * @return void
+     */
+    public static function tearDown()
+    {
+        Container::reset();
+    }
+
+    /**
+     * Make a connection fake.
+     *
+     * @param array $config
+     *
+     * @return ConnectionFake
+     */
+    public static function makeConnectionFake(array $config = [])
+    {
+        return ConnectionFake::make($config)->shouldBeConnected();
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/LdapExpectation.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/LdapExpectation.php
new file mode 100644
index 0000000..90a5fa2
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/LdapExpectation.php
@@ -0,0 +1,303 @@
+<?php
+
+namespace LdapRecord\Testing;
+
+use LdapRecord\LdapRecordException;
+use PHPUnit\Framework\Constraint\Constraint;
+use PHPUnit\Framework\Constraint\IsEqual;
+use UnexpectedValueException;
+
+class LdapExpectation
+{
+    /**
+     * The value to return from the expectation.
+     *
+     * @var mixed
+     */
+    protected $value;
+
+    /**
+     * The exception to throw from the expectation.
+     *
+     * @var null|LdapRecordException|\Exception
+     */
+    protected $exception;
+
+    /**
+     * The amount of times the expectation should be called.
+     *
+     * @var int
+     */
+    protected $count = 1;
+
+    /**
+     * The method that the expectation belongs to.
+     *
+     * @var string
+     */
+    protected $method;
+
+    /**
+     * The methods argument's.
+     *
+     * @var array
+     */
+    protected $args = [];
+
+    /**
+     * Whether the same expectation should be returned indefinitely.
+     *
+     * @var bool
+     */
+    protected $indefinitely = true;
+
+    /**
+     * Whether the expectation should return errors.
+     *
+     * @var bool
+     */
+    protected $errors = false;
+
+    /**
+     * The error number to return.
+     *
+     * @var int
+     */
+    protected $errorCode = 1;
+
+    /**
+     * The last error string to return.
+     *
+     * @var string
+     */
+    protected $errorMessage = '';
+
+    /**
+     * The diagnostic message string to return.
+     *
+     * @var string
+     */
+    protected $errorDiagnosticMessage = '';
+
+    /**
+     * Constructor.
+     *
+     * @param string $method
+     */
+    public function __construct($method)
+    {
+        $this->method = $method;
+    }
+
+    /**
+     * Set the arguments that the operation should receive.
+     *
+     * @param mixed $args
+     *
+     * @return $this
+     */
+    public function with($args)
+    {
+        $args = is_array($args) ? $args : func_get_args();
+
+        foreach ($args as $key => $arg) {
+            if (! $arg instanceof Constraint) {
+                $args[$key] = new IsEqual($arg);
+            }
+        }
+
+        $this->args = $args;
+
+        return $this;
+    }
+
+    /**
+     * Set the expected value to return.
+     *
+     * @param mixed $value
+     *
+     * @return $this
+     */
+    public function andReturn($value)
+    {
+        $this->value = $value;
+
+        return $this;
+    }
+
+    /**
+     * The error message to return from the expectation.
+     *
+     * @param int    $code
+     * @param string $error
+     * @param string $diagnosticMessage
+     *
+     * @return $this
+     */
+    public function andReturnError($code = 1, $error = '', $diagnosticMessage = '')
+    {
+        $this->errors = true;
+
+        $this->errorCode = $code;
+        $this->errorMessage = $error;
+        $this->errorDiagnosticMessage = $diagnosticMessage;
+
+        return $this;
+    }
+
+    /**
+     * Set the expected exception to throw.
+     *
+     * @param string|\Exception|LdapRecordException $exception
+     *
+     * @return $this
+     */
+    public function andThrow($exception)
+    {
+        if (is_string($exception)) {
+            $exception = new LdapRecordException($exception);
+        }
+
+        $this->exception = $exception;
+
+        return $this;
+    }
+
+    /**
+     * Set the expectation to be only called once.
+     *
+     * @return $this
+     */
+    public function once()
+    {
+        return $this->times(1);
+    }
+
+    /**
+     * Set the expectation to be only called twice.
+     *
+     * @return $this
+     */
+    public function twice()
+    {
+        return $this->times(2);
+    }
+
+    /**
+     * Set the expectation to be called the given number of times.
+     *
+     * @param int $count
+     *
+     * @return $this
+     */
+    public function times($count = 1)
+    {
+        $this->indefinitely = false;
+
+        $this->count = $count;
+
+        return $this;
+    }
+
+    /**
+     * Get the method the expectation belongs to.
+     *
+     * @return string
+     */
+    public function getMethod()
+    {
+        if (is_null($this->method)) {
+            throw new UnexpectedValueException('An expectation must have a method.');
+        }
+
+        return $this->method;
+    }
+
+    /**
+     * Get the expected call count.
+     *
+     * @return int
+     */
+    public function getExpectedCount()
+    {
+        return $this->count;
+    }
+
+    /**
+     * Get the expected arguments.
+     *
+     * @return Constraint[]
+     */
+    public function getExpectedArgs()
+    {
+        return $this->args;
+    }
+
+    /**
+     * Get the expected exception.
+     *
+     * @return null|\Exception|LdapRecordException
+     */
+    public function getExpectedException()
+    {
+        return $this->exception;
+    }
+
+    /**
+     * Get the expected value.
+     *
+     * @return mixed
+     */
+    public function getExpectedValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * Determine whether the expectation is returning an error.
+     *
+     * @return bool
+     */
+    public function isReturningError()
+    {
+        return $this->errors;
+    }
+
+    /**
+     * @return int
+     */
+    public function getExpectedErrorCode()
+    {
+        return $this->errorCode;
+    }
+
+    /**
+     * @return string
+     */
+    public function getExpectedErrorMessage()
+    {
+        return $this->errorMessage;
+    }
+
+    /**
+     * @return string
+     */
+    public function getExpectedErrorDiagnosticMessage()
+    {
+        return $this->errorDiagnosticMessage;
+    }
+
+    /**
+     * Decrement the call count of the expectation.
+     *
+     * @return $this
+     */
+    public function decrementCallCount()
+    {
+        if (! $this->indefinitely) {
+            $this->count -= 1;
+        }
+
+        return $this;
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/LdapFake.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/LdapFake.php
new file mode 100644
index 0000000..7ba0e15
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/directorytree/ldaprecord/src/Testing/LdapFake.php
@@ -0,0 +1,525 @@
+<?php
+
+namespace LdapRecord\Testing;
+
+use Exception;
+use LdapRecord\DetailedError;
+use LdapRecord\DetectsErrors;
+use LdapRecord\HandlesConnection;
+use LdapRecord\LdapInterface;
+use LdapRecord\Support\Arr;
+use PHPUnit\Framework\Assert as PHPUnit;
+use PHPUnit\Framework\Constraint\Constraint;
+
+class LdapFake implements LdapInterface
+{
+    use HandlesConnection, DetectsErrors;
+
+    /**
+     * The expectations of the LDAP fake.
+     *
+     * @var array
+     */
+    protected $expectations = [];
+
+    /**
+     * The default fake error number.
+     *
+     * @var int
+     */
+    protected $errNo = 1;
+
+    /**
+     * The default fake last error string.
+     *
+     * @var string
+     */
+    protected $lastError = '';
+
+    /**
+     * The default fake diagnostic message string.
+     *
+     * @var string
+     */
+    protected $diagnosticMessage = '';
+
+    /**
+     * Create a new expected operation.
+     *
+     * @param string $method
+     *
+     * @return LdapExpectation
+     */
+    public static function operation($method)
+    {
+        return new LdapExpectation($method);
+    }
+
+    /**
+     * Set the user that will pass binding.
+     *
+     * @param string $dn
+     *
+     * @return $this
+     */
+    public function shouldAuthenticateWith($dn)
+    {
+        return $this->expect(
+            static::operation('bind')->with($dn, PHPUnit::anything())->andReturn(true)
+        );
+    }
+
+    /**
+     * Add an LDAP method expectation.
+     *
+     * @param LdapExpectation|array $expectations
+     *
+     * @return $this
+     */
+    public function expect($expectations = [])
+    {
+        $expectations = Arr::wrap($expectations);
+
+        foreach ($expectations as $key => $expectation) {
+            // If the key is non-numeric, we will assume
+            // that the string is the method name and
+            // the expectation is the return value.
+            if (! is_numeric($key)) {
+                $expectation = static::operation($key)->andReturn($expectation);
+            }
+
+            if (! $expectation instanceof LdapExpectation) {
+                $expectation = static::operation($expectation);
+            }
+
+            $this->expectations[$expectation->getMethod()][] = $expectation;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Determine if the method has any expectations.
+     *
+     * @param string $method
+     *
+     * @return bool
+     */
+    public function hasExpectations($method)
+    {
+        return count($this->getExpectations($method)) > 0;
+    }
+
+    /**
+     * Get expectations by method.
+     *
+     * @param string $method
+     *
+     * @return LdapExpectation[]|mixed
+     */
+    public function getExpectations($method)
+    {
+        return $this->expectations[$method] ?? [];
+    }
+
+    /**
+     * Remove an expectation by method and key.
+     *
+     * @param string $method
+     * @param int    $key
+     *
+     * @return void
+     */
+    public function removeExpectation($method, $key)
+    {
+        unset($this->expectations[$method][$key]);
+    }
+
+    /**
+     * Set the error number of a failed bind attempt.
+     *
+     * @param int $number
+     *
+     * @return $this
+     */
+    public function shouldReturnErrorNumber($number = 1)
+    {
+        $this->errNo = $number;
+
+        return $this;
+    }
+
+    /**
+     * Set the last error of a failed bind attempt.
+     *
+     * @param string $message
+     *
+     * @return $this
+     */
+    public function shouldReturnError($message = '')
+    {
+        $this->lastError = $message;
+
+        return $this;
+    }
+
+    /**
+     * Set the diagnostic message of a failed bind attempt.
+     *
+     * @param string $message
+     *
+     * @return $this
+     */
+    public function shouldReturnDiagnosticMessage($message = '')
+    {
+        $this->diagnosticMessage = $message;
+
+        return $this;
+    }
+
+    /**
+     * Return a fake error number.
+     *
+     * @return int
+     */
+    public function errNo()
+    {
+        return $this->errNo;
+    }
+
+    /**
+     * Return a fake error.
+     *
+     * @return string
+     */
+    public function getLastError()
+    {
+        return $this->lastError;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getDiagnosticMessage()
+    {
+        return $this->diagnosticMessage;
+    }
+
+    /**
+     * Return a fake detailed error.
+     *
+     * @return DetailedError
+     */
+    public function getDetailedError()
+    {
+        return new DetailedError(
+            $this->errNo(),
+            $this->getLastError(),
+            $this->getDiagnosticMessage()
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getEntries($searchResults)
+    {
+        return $searchResults;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function isUsingSSL()
+    {
+        return $this->hasExpectations('isUsingSSL')
+            ? $this->resolveExpectation('isUsingSSL')
+            : $this->useSSL;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function isUsingTLS()
+    {
+        return $this->hasExpectations('isUsingTLS')
+            ? $this->resolveExpectation('isUsingTLS')
+            : $this->useTLS;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function isBound()
+    {
+        return $this->hasExpectations('isBound')
+            ? $this->resolveExpectation('isBound')
+            : $this->bound;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function setOption($option, $value)
+    {
+        return $this->hasExpectations('setOption')
+            ? $this->resolveExpectation('setOption', func_get_args())
+            : true;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getOption($option, &$value = null)
+    {
+        return $this->resolveExpectation('getOption', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function startTLS()
+    {
+        return $this->resolveExpectation('startTLS', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function connect($hosts = [], $port = 389)
+    {
+        $this->bound = false;
+
+        $this->host = $this->makeConnectionUris($hosts, $port);
+
+        return $this->connection = $this->hasExpectations('connect')
+            ? $this->resolveExpectation('connect', func_get_args())
+            : true;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function close()
+    {
+        $this->connection = null;
+        $this->bound = false;
+        $this->host = null;
+
+        return $this->hasExpectations('close')
+            ? $this->resolveExpectation('close')
+            : true;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function bind($username, $password)
+    {
+        return $this->bound = $this->resolveExpectation('bind', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function search($dn, $filter, array $fields, $onlyAttributes = false, $size = 0, $time = 0, $deref = null, $serverControls = [])
+    {
+        return $this->resolveExpectation('search', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function listing($dn, $filter, array $fields, $onlyAttributes = false, $size = 0, $time = 0, $deref = null, $serverControls = [])
+    {
+        return $this->resolveExpectation('listing', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function read($dn, $filter, array $fields, $onlyAttributes = false, $size = 0, $time = 0, $deref = null, $serverControls = [])
+    {
+        return $this->resolveExpectation('read', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function parseResult($result, &$errorCode, &$dn, &$errorMessage, &$referrals, &$serverControls = [])
+    {
+        return $this->resolveExpectation('parseResult', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function add($dn, array $entry)
+    {
+        return $this->resolveExpectation('add', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function delete($dn)
+    {
+        return $this->resolveExpectation('delete', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function rename($dn, $newRdn, $newParent, $deleteOldRdn = false)
+    {
+        return $this->resolveExpectation('rename', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function modify($dn, array $entry)
+    {
+        return $this->resolveExpectation('modify', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function modifyBatch($dn, array $values)
+    {
+        return $this->resolveExpectation('modifyBatch', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function modAdd($dn, array $entry)
+    {
+        return $this->resolveExpectation('modAdd', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function modReplace($dn, array $entry)
+    {
+        return $this->resolveExpectation('modReplace', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function modDelete($dn, array $entry)
+    {
+        return $this->resolveExpectation('modDelete', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function controlPagedResult($pageSize = 1000, $isCritical = false, $cookie = '')
+    {
+        return $this->resolveExpectation('controlPagedResult', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function controlPagedResultResponse($result, &$cookie)
+    {
+        return $this->resolveExpectation('controlPagedResultResponse', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function freeResult($result)
+    {
+        return $this->resolveExpectation('freeResult', func_get_args());
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function err2Str($number)
+    {
+        return $this->resolveExpectation('err2Str', func_get_args());
+    }
+
+    /**
+     * Resolve the methods expectations.
+     *
+     * @param string $method
+     * @param array  $args
+     *
+     * @throws Exception
+     *
+     * @return mixed
+     */
+    protected function resolveExpectation($method, array $args = [])
+    {
+        foreach ($this->getExpectations($method) as $key => $expectation) {
+            $this->assertMethodArgumentsMatch($method, $expectation->getExpectedArgs(), $args);
+
+            $expectation->decrementCallCount();
+
+            if ($expectation->getExpectedCount() === 0) {
+                $this->removeExpectation($method, $key);
+            }
+
+            if (! is_null($exception = $expectation->getExpectedException())) {
+                throw $exception;
+            }
+
+            if ($expectation->isReturningError()) {
+                $this->applyExpectationError($expectation);
+            }
+
+            return $expectation->getExpectedValue();
+        }
+
+        throw new Exception("LDAP method [$method] was unexpected.");
+    }
+
+    /**
+     * Apply the expectation error to the fake.
+     *
+     * @param LdapExpectation $expectation
+     *
+     * @return void
+     */
+    protected function applyExpectationError(LdapExpectation $expectation)
+    {
+        $this->shouldReturnError($expectation->getExpectedErrorMessage());
+        $this->shouldReturnErrorNumber($expectation->getExpectedErrorCode());
+        $this->shouldReturnDiagnosticMessage($expectation->getExpectedErrorDiagnosticMessage());
+    }
+
+    /**
+     * Assert that the expected arguments match the operations arguments.
+     *
+     * @param string       $method
+     * @param Constraint[] $expectedArgs
+     * @param array        $methodArgs
+     *
+     * @return void
+     */
+    protected function assertMethodArgumentsMatch($method, array $expectedArgs = [], array $methodArgs = [])
+    {
+        foreach ($expectedArgs as $key => $constraint) {
+            $argNumber = $key + 1;
+
+            PHPUnit::assertArrayHasKey(
+                $key,
+                $methodArgs,
+                "LDAP method [$method] argument #{$argNumber} does not exist."
+            );
+
+            $constraint->evaluate(
+                $methodArgs[$key],
+                "LDAP method [$method] expectation failed."
+            );
+        }
+    }
+}