Compare commits

...
Author SHA1 Message Date
FreddleSpl0it 92ad6c5e6d [Rspamd] Update to 4.2.3 2026-10-28 12:19:53 +01:00
FreddleSpl0it aa7388810c Merge pull request #7568 from mailcow/feat/compose-update
[Web] Update composer libraries
2026-10-28 12:01:04 +01:00
FreddleSpl0it 4dd7aead73 [Web] Store PKCE data of OAuth2 authorization codes 2026-10-28 11:57:46 +01:00
FreddleSpl0it bd8c784118 [Web] Update composer libraries 2026-10-28 11:56:29 +01:00
FreddleSpl0it 9cc8ac2908 Merge pull request #7567 from mailcow/feat/netfilter-rework
[Netfilter] Rework: robust bans, no restart loops, identity provider outages are no failed logins
2026-10-28 11:24:29 +01:00
FreddleSpl0it 002400315d Merge pull request #7566 from mailcow/feat/groups
[Web][Dovecot][SOGo][DockerApi] Add mailbox groups, shared mailboxes and identity provider sync
2026-10-28 11:21:58 +01:00
FreddleSpl0it 8934a84d18 Merge pull request #7547 from mailcow/feat/apikey-rework
[Web] Rework API keys: multiple keys + locked service keys from mailcow.conf
2026-10-28 11:18:47 +01:00
FreddleSpl0it 5ce88b5795 Merge pull request #7546 from mailcow/feat/imapsync-rework
[Web][Dovecot] Rework imapsync: sync sources, OAuth2, Python runner
2026-10-28 11:17:09 +01:00
FreddleSpl0it b2b21b1a85 Merge pull request #7551 from mailcow/renovate/tianon-gosu-1.x
Update dependency tianon/gosu to v1.20
2026-10-28 09:05:19 +01:00
FreddleSpl0it 4b1b9362f3 Merge pull request #7555 from mailcow/renovate/redis-7.x
Update redis Docker tag to v7.4.12
2026-10-28 09:04:55 +01:00
FreddleSpl0it fb32d8d345 Merge pull request #7563 from mailcow/feat/alpine3.24
Feat/alpine3.24
2026-10-28 09:04:34 +01:00
FreddleSpl0it af5d0e3d29 [Dovecot] Update base to Alpine 3.24, build Dovecot 2.3 from Alpine 3.21 packaging 2026-10-28 09:00:45 +01:00
FreddleSpl0it 4884ed0cbf [Olefy] Update base to Alpine 3.24, fix event loop for Python 3.14 2026-10-28 08:51:33 +01:00
FreddleSpl0it 8aaf68ffb5 [Unbound] Update to 1.26.2, base Alpine 3.24 2026-10-28 08:50:42 +01:00
FreddleSpl0it 503e64fe85 [ACME][Dockerapi][Netfilter][Watchdog] Update base to Alpine 3.24 2026-10-28 08:49:57 +01:00
renovate[bot] 0445f85d7d Update redis Docker tag to v7.4.12
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2026-10-27 00:27:59 +00:00
renovate[bot] 714ca5a3d8 Update dependency tianon/gosu to v1.20
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2026-10-25 13:00:37 +00:00
FreddleSpl0it 7d27460fee Merge branch 'staging' into feat/imapsync-rework 2026-10-23 11:49:45 +02:00
milkmakerandciri-cuervo 82b1cf7198 [Web] Updated lang.es-es.json (#7542)
Co-authored-by: ciri-cuervo <nicolascirigliano@gmail.com>
2026-10-22 17:54:52 +02:00
1311 changed files with 71911 additions and 24547 deletions

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.23
FROM alpine:3.24
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.23
FROM alpine:3.24
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
+43 -13
View File
@@ -1,12 +1,48 @@
FROM alpine:3.21
# Alpine >= 3.22 only ships Dovecot 2.4, Dovecot 2.3 is built from the Alpine 3.21 packaging
FROM alpine:3.24 AS builder
# Last commit of the aports 3.21-stable branch
ARG APORTS_COMMIT=55126a11a4b9dcd14de3068e3348e9951d144ca6
RUN apk add --no-cache alpine-sdk git \
&& git init -q /aports \
&& cd /aports \
&& git remote add origin https://github.com/alpinelinux/aports.git \
&& git sparse-checkout set main/dovecot community/dovecot-fts-flatcurve \
&& git fetch -q --depth 1 --filter=blob:none origin ${APORTS_COMMIT} \
&& git checkout -q FETCH_HEAD \
&& abuild-keygen -a -n \
&& cp /root/.abuild/*.rsa.pub /etc/apk/keys/ \
&& apk update \
&& cd /aports/main/dovecot \
# newer gettext does not overwrite the shipped config.rpath without -f
&& sed -i 's/autoreconf -vi/autoreconf -fvi/' APKBUILD \
&& abuild -F -r \
# flatcurve must be built against the Dovecot 2.3 headers
&& apk add --no-cache /root/packages/main/*/dovecot-2*.apk /root/packages/main/*/dovecot-dev-*.apk \
&& cd /aports/community/dovecot-fts-flatcurve \
&& abuild -F -r \
&& mkdir /packages \
&& cp /root/.abuild/*.rsa.pub /packages/ \
&& for pkg in dovecot dovecot-dev dovecot-lmtpd dovecot-lua dovecot-ldap dovecot-mysql dovecot-sql \
dovecot-submissiond dovecot-pigeonhole-plugin dovecot-pop3d dovecot-fts-flatcurve; do \
cp /root/packages/*/*/${pkg}-[0-9]*.apk /packages/; \
done
FROM alpine:3.24
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
ARG GOSU_VERSION=1.19
ARG GOSU_VERSION=1.20
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
# MariaDB Connector/C >= 3.4 refuses DB servers without TLS, this covers Perl DBI, client.cnf covers Dovecot
ENV MARIADB_TLS_DISABLE_PEER_VERIFICATION=1
COPY --from=builder /packages /tmp/packages
# Add groups and users before installing Dovecot to not break compatibility
RUN addgroup -g 5000 vmail \
@@ -18,6 +54,7 @@ RUN addgroup -g 5000 vmail \
&& adduser -D -u 5000 -G vmail -h /var/vmail vmail \
&& adduser -D -G dovecot -u 401 -h /dev/null -s /sbin/nologin dovecot \
&& adduser -D -G dovenull -u 402 -h /dev/null -s /sbin/nologin dovenull \
&& cp /tmp/packages/*.rsa.pub /etc/apk/keys/ \
&& apk add --no-cache --update \
bash \
bind-tools \
@@ -98,22 +135,15 @@ RUN addgroup -g 5000 vmail \
supervisor \
tzdata \
wget \
dovecot \
dovecot-dev \
dovecot-lmtpd \
dovecot-lua \
dovecot-ldap \
dovecot-mysql \
dovecot-sql \
dovecot-submissiond \
dovecot-pigeonhole-plugin \
dovecot-pop3d \
dovecot-fts-flatcurve \
/tmp/packages/*.apk \
&& rm -rf /tmp/packages \
&& arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$arch" \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true
# Dovecot's MySQL driver reads [client] from /etc/my.cnf, Connector/C ignores the !includedir there
COPY client.cnf /etc/my.cnf
COPY trim_logs.sh /usr/local/bin/trim_logs.sh
COPY clean_q_aged.sh /usr/local/bin/clean_q_aged.sh
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
+3
View File
@@ -0,0 +1,3 @@
[client]
ssl = false
ssl-verify-server-cert = false
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.23
FROM alpine:3.24
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.21
FROM alpine:3.24
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
+4 -3
View File
@@ -67,7 +67,7 @@ logger.debug('olefy listen address string: {} (type {})'.format(olefy_listen_add
if not olefy_listen_addr_string:
olefy_listen_addr = ""
else:
addr_re = re.compile('[\[" \]]')
addr_re = re.compile(r'[\[" \]]')
olefy_listen_addr = addr_re.sub('', olefy_listen_addr_string.replace("'", "")).split(',')
# log runtime variables
@@ -206,8 +206,9 @@ class AIO(asyncio.Protocol):
self.transport.close()
# start the listeners
loop = asyncio.get_event_loop()
# start the listeners, Python >= 3.14 no longer creates a loop in get_event_loop()
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# each client connection will create a new protocol instance
coro = loop.create_server(AIO, olefy_listen_addr, olefy_listen_port)
server = loop.run_until_complete(coro)
+1 -1
View File
@@ -2,7 +2,7 @@ FROM debian:trixie-slim
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG RSPAMD_VER=rspamd_4.2.1-1~b7a16ae
ARG RSPAMD_VER=rspamd_4.2.3-1~50bde75
ARG CODENAME=trixie
ENV LC_ALL=C
+1 -1
View File
@@ -17,7 +17,7 @@ ARG SOPE_VERSION=SOPE-5.12.12
# Security patches to apply (space-separated commit hashes)
ARG SOGO_SECURITY_PATCHES=""
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
ARG GOSU_VERSION=1.19
ARG GOSU_VERSION=1.20
ENV LC_ALL=C
# Install dependencies, build SOPE and SOGo, then clean up (all in one layer to minimize image size)
+2 -2
View File
@@ -1,10 +1,10 @@
FROM alpine:3.23
FROM alpine:3.24
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
# install unbound from alpine:edge to get security patches
# minimum version is pinned
RUN apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main "unbound>=1.26.1-r0"
RUN apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main "unbound>=1.26.2-r0"
# install other packages from regular alpine stable repo
RUN apk add --update --no-cache \
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.23
FROM alpine:3.24
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
+3 -1
View File
@@ -1604,7 +1604,9 @@ function init_db_schema()
"redirect_uri" => "VARCHAR(2000)",
"expires" => "TIMESTAMP NOT NULL",
"scope" => "VARCHAR(4000)",
"id_token" => "VARCHAR(1000)"
"id_token" => "VARCHAR(1000)",
"code_challenge" => "VARCHAR(1000)",
"code_challenge_method" => "VARCHAR(20)"
),
"keys" => array(
"primary" => array(
+1 -1
View File
@@ -10,7 +10,7 @@
"mustangostang/spyc": "^0.6.3",
"directorytree/ldaprecord": "^3.3",
"twig/twig": "^3.0",
"stevenmaguire/oauth2-keycloak": "^4.0",
"stevenmaguire/oauth2-keycloak": "^6.1",
"league/oauth2-client": "^2.7",
"bacon/bacon-qr-code": "^2.0"
},
+825 -472
View File
File diff suppressed because it is too large. Load diff
+1 -4
View File
@@ -14,10 +14,7 @@ if (PHP_VERSION_ID < 50600) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
throw new RuntimeException($err);
}
require_once __DIR__ . '/composer/autoload_real.php';
+34 -12
View File
@@ -12,6 +12,7 @@
namespace Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
if (PHP_VERSION_ID < 80000) {
@@ -23,18 +24,17 @@ if (PHP_VERSION_ID < 80000) {
{
private $handle;
private $position;
private $realpath;
public function stream_open($path, $mode, $options, &$opened_path)
{
// get rid of composer-bin-proxy:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 21);
$opened_path = realpath($opened_path) ?: $opened_path;
$this->handle = fopen($opened_path, $mode);
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 17);
$this->realpath = realpath($opened_path) ?: $opened_path;
$opened_path = $this->realpath;
$this->handle = fopen($this->realpath, $mode);
$this->position = 0;
// remove all traces of this stream wrapper once it has been used
stream_wrapper_unregister('composer-bin-proxy');
return (bool) $this->handle;
}
@@ -66,6 +66,16 @@ if (PHP_VERSION_ID < 80000) {
return $operation ? flock($this->handle, $operation) : true;
}
public function stream_seek($offset, $whence)
{
if (0 === fseek($this->handle, $offset, $whence)) {
$this->position = ftell($this->handle);
return true;
}
return false;
}
public function stream_tell()
{
return $this->position;
@@ -78,20 +88,32 @@ if (PHP_VERSION_ID < 80000) {
public function stream_stat()
{
return fstat($this->handle);
return array();
}
public function stream_set_option($option, $arg1, $arg2)
{
return true;
}
public function url_stat($path, $flags)
{
$path = substr($path, 17);
if (file_exists($path)) {
return stat($path);
}
return false;
}
}
}
if (function_exists('stream_wrapper_register') && stream_wrapper_register('composer-bin-proxy', 'Composer\BinProxyWrapper')) {
include("composer-bin-proxy://" . __DIR__ . '/..'.'/matthiasmullie/minify/bin/minifycss');
exit(0);
if (
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
return include("phpvfscomposer://" . __DIR__ . '/..'.'/matthiasmullie/minify/bin/minifycss');
}
}
include __DIR__ . '/..'.'/matthiasmullie/minify/bin/minifycss';
return include __DIR__ . '/..'.'/matthiasmullie/minify/bin/minifycss';
+34 -12
View File
@@ -12,6 +12,7 @@
namespace Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
if (PHP_VERSION_ID < 80000) {
@@ -23,18 +24,17 @@ if (PHP_VERSION_ID < 80000) {
{
private $handle;
private $position;
private $realpath;
public function stream_open($path, $mode, $options, &$opened_path)
{
// get rid of composer-bin-proxy:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 21);
$opened_path = realpath($opened_path) ?: $opened_path;
$this->handle = fopen($opened_path, $mode);
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 17);
$this->realpath = realpath($opened_path) ?: $opened_path;
$opened_path = $this->realpath;
$this->handle = fopen($this->realpath, $mode);
$this->position = 0;
// remove all traces of this stream wrapper once it has been used
stream_wrapper_unregister('composer-bin-proxy');
return (bool) $this->handle;
}
@@ -66,6 +66,16 @@ if (PHP_VERSION_ID < 80000) {
return $operation ? flock($this->handle, $operation) : true;
}
public function stream_seek($offset, $whence)
{
if (0 === fseek($this->handle, $offset, $whence)) {
$this->position = ftell($this->handle);
return true;
}
return false;
}
public function stream_tell()
{
return $this->position;
@@ -78,20 +88,32 @@ if (PHP_VERSION_ID < 80000) {
public function stream_stat()
{
return fstat($this->handle);
return array();
}
public function stream_set_option($option, $arg1, $arg2)
{
return true;
}
public function url_stat($path, $flags)
{
$path = substr($path, 17);
if (file_exists($path)) {
return stat($path);
}
return false;
}
}
}
if (function_exists('stream_wrapper_register') && stream_wrapper_register('composer-bin-proxy', 'Composer\BinProxyWrapper')) {
include("composer-bin-proxy://" . __DIR__ . '/..'.'/matthiasmullie/minify/bin/minifyjs');
exit(0);
if (
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
return include("phpvfscomposer://" . __DIR__ . '/..'.'/matthiasmullie/minify/bin/minifyjs');
}
}
include __DIR__ . '/..'.'/matthiasmullie/minify/bin/minifyjs';
return include __DIR__ . '/..'.'/matthiasmullie/minify/bin/minifyjs';
@@ -0,0 +1,74 @@
name: Test Suite
on:
push:
branches:
- main
pull_request:
jobs:
test:
runs-on: ubuntu-latest
services:
redis:
image: redis
ports:
- 6379:6379
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
mongodb:
image: mongo
ports:
- 27017:27017
myriadb:
image: mariadb
env:
MYSQL_ROOT_PASSWORD: root
ports:
- 3808:3808
- 3306:3306
postgres:
image: postgres
env:
POSTGRES_DB: oauth2_server_php
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: --health-cmd="pg_isready -h localhost" --health-interval=10s --health-timeout=5s --health-retries=5
strategy:
matrix:
php: [ 7.2, 7.3, 7.4, "8.0", 8.1, 8.2 ]
name: "PHP ${{ matrix.php }} Unit Test"
steps:
- uses: actions/checkout@v2
- uses: codecov/codecov-action@v1
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mongodb, mbstring, intl, redis, pdo_mysql
- name: Install composer dependencies
uses: nick-invision/retry@v1
with:
timeout_minutes: 10
max_attempts: 3
command: composer install
- name: Run PHPUnit
run: vendor/bin/phpunit -v
phpstan:
name: "PHPStan"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.1
- name: Install composer dependencies
uses: nick-invision/retry@v1
with:
timeout_minutes: 10
max_attempts: 3
command: composer install
- name: Run PHPStan
run: |
composer require phpstan/phpstan
vendor/bin/phpstan analyse --level=0 src/
@@ -1,8 +1,6 @@
oauth2-server-php
=================
[![Build Status](https://travis-ci.org/bshaffer/oauth2-server-php.svg?branch=master)](https://travis-ci.org/bshaffer/oauth2-server-php)
[![Total Downloads](https://poser.pugx.org/bshaffer/oauth2-server-php/downloads.png)](https://packagist.org/packages/bshaffer/oauth2-server-php)
[![Total Downloads](https://poser.pugx.org/bshaffer/oauth2-server-php/downloads)](https://packagist.org/packages/bshaffer/oauth2-server-php)
View the [complete documentation](https://bshaffer.github.io/oauth2-server-php-docs/)
@@ -16,21 +16,21 @@
"psr-0": { "OAuth2": "src/" }
},
"require":{
"php":">=5.3.9"
"php":">=7.2"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"aws/aws-sdk-php": "~2.8",
"firebase/php-jwt": "~2.2",
"predis/predis": "dev-master",
"phpunit/phpunit": "^7.5||^8.0",
"aws/aws-sdk-php": "^2.8",
"firebase/php-jwt": "^6.4",
"predis/predis": "^1.1",
"thobbs/phpcassa": "dev-master",
"mongodb/mongodb": "^1.1"
"yoast/phpunit-polyfills": "^1.0"
},
"suggest": {
"predis/predis": "Required to use Redis storage",
"thobbs/phpcassa": "Required to use Cassandra storage",
"aws/aws-sdk-php": "~2.8 is required to use DynamoDB storage",
"firebase/php-jwt": "~2.2 is required to use JWT features",
"firebase/php-jwt": "~v6.4 is required to use JWT features",
"mongodb/mongodb": "^1.1 is required to use MongoDB storage"
}
}
@@ -39,7 +39,7 @@ class Autoloader
* Handles autoloading of classes.
*
* @param string $class - A class name.
* @return boolean - Returns true if the class has been loaded
* @return void
*/
public function autoload($class)
{
@@ -112,7 +112,7 @@ class HttpBasic implements ClientAssertionTypeInterface
*
* @ingroup oauth2_section_2
*/
public function getClientCredentials(RequestInterface $request, ResponseInterface $response = null)
public function getClientCredentials(RequestInterface $request, ?ResponseInterface $response = null)
{
if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) {
return array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW'));
@@ -78,7 +78,7 @@ class AuthorizeController implements AuthorizeControllerInterface
* );
* @endcode
*/
public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null)
public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ?ScopeInterface $scopeUtil = null)
{
$this->clientStorage = $clientStorage;
$this->responseTypes = $responseTypes;
@@ -87,6 +87,7 @@ class AuthorizeController implements AuthorizeControllerInterface
'enforce_state' => true,
'require_exact_redirect_uri' => true,
'redirect_status_code' => 302,
'enforce_pkce' => false,
), $config);
if (is_null($scopeUtil)) {
@@ -47,7 +47,7 @@ class ResourceController implements ResourceControllerInterface
* @param array $config
* @param ScopeInterface $scopeUtil
*/
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null)
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ?ScopeInterface $scopeUtil = null)
{
$this->tokenType = $tokenType;
$this->tokenStorage = $tokenStorage;
@@ -13,7 +13,7 @@ use OAuth2\ResponseInterface;
* @code
* if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) {
* $response->send(); // authorization failed
* exit();
* die();
* }
* return json_encode($resource); // valid token! Send the stuff!
* @endcode
@@ -54,7 +54,7 @@ class TokenController implements TokenControllerInterface
* @param ScopeInterface $scopeUtil
* @throws InvalidArgumentException
*/
public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null)
public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ?ClientAssertionTypeInterface $clientAssertionType = null, ?ScopeInterface $scopeUtil = null)
{
if (is_null($clientAssertionType)) {
foreach ($grantTypes as $grantType) {
@@ -2,6 +2,9 @@
namespace OAuth2\Encryption;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
/**
* Bridge file to use the firebase/php-jwt package for JWT encoding and decoding.
* @author Francis Chuang <francis.chuang@gmail.com>
@@ -10,26 +13,36 @@ class FirebaseJwt implements EncryptionInterface
{
public function __construct()
{
if (!class_exists('\JWT')) {
if (!class_exists(JWT::class)) {
throw new \ErrorException('firebase/php-jwt must be installed to use this feature. You can do this by running "composer require firebase/php-jwt"');
}
}
public function encode($payload, $key, $alg = 'HS256', $keyId = null)
{
return \JWT::encode($payload, $key, $alg, $keyId);
return JWT::encode($payload, $key, $alg, $keyId);
}
public function decode($jwt, $key = null, $allowedAlgorithms = null)
{
try {
//Maintain BC: Do not verify if no algorithms are passed in.
if (!$allowedAlgorithms) {
$key = null;
$tks = \explode('.', $jwt);
if (\count($tks) === 3) {
[$headb64] = $tks;
$headerRaw = JWT::urlsafeB64Decode($headb64);
if (($header = JWT::jsonDecode($headerRaw))) {
$key = new Key($key, $header->alg);
}
}
} elseif(is_array($allowedAlgorithms)) {
$key = new Key($key, $allowedAlgorithms[0]);
} else {
$key = new Key($key, $allowedAlgorithms);
}
return (array)\JWT::decode($jwt, $key, $allowedAlgorithms);
return (array) JWT::decode($jwt, $key);
} catch (\Exception $e) {
return false;
}
@@ -37,11 +50,11 @@ class FirebaseJwt implements EncryptionInterface
public function urlSafeB64Encode($data)
{
return \JWT::urlsafeB64Encode($data);
return JWT::urlsafeB64Encode($data);
}
public function urlSafeB64Decode($b64)
{
return \JWT::urlsafeB64Decode($b64);
return JWT::urlsafeB64Decode($b64);
}
}
@@ -84,6 +84,41 @@ class AuthorizationCode implements GrantTypeInterface
return false;
}
if (isset($authCode['code_challenge']) && $authCode['code_challenge']) {
if (!($code_verifier = $request->request('code_verifier'))) {
$response->setError(400, 'code_verifier_missing', "The PKCE code verifier parameter is required.");
return false;
}
// Validate code_verifier according to RFC-7636
// @see: https://tools.ietf.org/html/rfc7636#section-4.1
if (preg_match('/^[A-Za-z0-9-._~]{43,128}$/', $code_verifier) !== 1) {
$response->setError(400, 'code_verifier_invalid', "The PKCE code verifier parameter is invalid.");
return false;
}
$code_verifier = $request->request('code_verifier');
switch ($authCode['code_challenge_method']) {
case 'S256':
$code_verifier_hashed = strtr(rtrim(base64_encode(hash('sha256', $code_verifier, true)), '='), '+/', '-_');
break;
case 'plain':
$code_verifier_hashed = $code_verifier;
break;
default:
$response->setError(400, 'code_challenge_method_invalid', "Unknown PKCE code challenge method.");
return FALSE;
}
if ($code_verifier_hashed !== $authCode['code_challenge']) {
$response->setError(400, 'code_verifier_mismatch', "The PKCE code verifier parameter does not match the code challenge.");
return FALSE;
}
}
if (!isset($authCode['code'])) {
$authCode['code'] = $code; // used to expire the code after the access token is granted
}
@@ -37,7 +37,7 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
* @param EncryptionInterface|JWT $jwtUtil - OPTONAL The class used to decode, encode and verify JWTs.
* @param array $config
*/
public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array())
public function __construct(JwtBearerInterface $storage, $audience, ?EncryptionInterface $jwtUtil = null, array $config = array())
{
$this->storage = $storage;
$this->audience = $audience;
@@ -46,13 +46,13 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
$jwtUtil = new Jwt();
}
$this->config = array_merge(array(
$config = array_merge(array(
'allowed_algorithms' => array('RS256', 'RS384', 'RS512')
), $config);
$this->jwtUtil = $jwtUtil;
$this->allowedAlgorithms = $this->config['allowed_algorithms'];
$this->allowedAlgorithms = $config['allowed_algorithms'];
}
/**
@@ -127,7 +127,7 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
}
// Check expiration
if (ctype_digit($jwt['exp'])) {
if (ctype_digit((string)$jwt['exp'])) {
if ($jwt['exp'] <= time()) {
$response->setError(400, 'invalid_grant', "JWT has expired");
@@ -141,7 +141,7 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
// Check the not before time
if ($notBefore = $jwt['nbf']) {
if (ctype_digit($notBefore)) {
if (ctype_digit((string)$notBefore)) {
if ($notBefore > time()) {
$response->setError(400, 'invalid_grant', "JWT cannot be used before the Not Before (nbf) time");
@@ -16,6 +16,16 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
*/
private $nonce;
/**
* @var mixed
*/
protected $code_challenge;
/**
* @var mixed
*/
protected $code_challenge_method;
/**
* Set not authorized response
*
@@ -65,6 +75,10 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
// add the nonce to return with the redirect URI
$params['nonce'] = $this->nonce;
// Add PKCE code challenge.
$params['code_challenge'] = $this->code_challenge;
$params['code_challenge_method'] = $this->code_challenge_method;
return $params;
}
@@ -90,6 +104,32 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
$this->nonce = $nonce;
$code_challenge = $request->query('code_challenge');
$code_challenge_method = $request->query('code_challenge_method');
if ($this->config['enforce_pkce']) {
if (!$code_challenge) {
$response->setError(400, 'missing_code_challenge', 'This application requires you provide a PKCE code challenge');
return false;
}
if (preg_match('/^[A-Za-z0-9-._~]{43,128}$/', $code_challenge) !== 1) {
$response->setError(400, 'invalid_code_challenge', 'The PKCE code challenge supplied is invalid');
return false;
}
if (!in_array($code_challenge_method, array('plain', 'S256'), true)) {
$response->setError(400, 'missing_code_challenge_method', 'This application requires you specify a PKCE code challenge method');
return false;
}
}
$this->code_challenge = $code_challenge;
$this->code_challenge_method = $code_challenge_method;
return true;
}
@@ -30,7 +30,7 @@ class UserInfoController extends ResourceController implements UserInfoControlle
* @param array $config
* @param ScopeInterface $scopeUtil
*/
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ScopeInterface $scopeUtil = null)
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ?ScopeInterface $scopeUtil = null)
{
parent::__construct($tokenType, $tokenStorage, $config, $scopeUtil);
@@ -31,9 +31,9 @@ class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCo
// build the URL to redirect to
$result = array('query' => array());
$params += array('scope' => null, 'state' => null, 'id_token' => null);
$params += array('scope' => null, 'state' => null, 'id_token' => null, 'code_challenge' => null, 'code_challenge_method' => null);
$result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope'], $params['id_token']);
$result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope'], $params['id_token'], $params['code_challenge'], $params['code_challenge_method']);
if (isset($params['state'])) {
$result['query']['state'] = $params['state'];
@@ -56,10 +56,10 @@ class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCo
* @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4
*/
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null)
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
$code = $this->generateAuthorizationCode();
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope, $id_token);
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope, $id_token, $code_challenge, $code_challenge_method);
return $code;
}
@@ -38,7 +38,7 @@ class IdToken implements IdTokenInterface
* @param EncryptionInterface $encryptionUtil
* @throws LogicException
*/
public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null)
public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), ?EncryptionInterface $encryptionUtil = null)
{
$this->userClaimsStorage = $userClaimsStorage;
$this->publicKeyStorage = $publicKeyStorage;
@@ -33,5 +33,5 @@ interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
*
* @ingroup oauth2_section_4
*/
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null);
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null);
}
@@ -34,7 +34,7 @@ class Request implements RequestInterface
*
* @api
*/
public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null)
public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, ?array $headers = null)
{
$this->initialize($query, $request, $attributes, $cookies, $files, $server, $content, $headers);
}
@@ -55,7 +55,7 @@ class Request implements RequestInterface
*
* @api
*/
public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null)
public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, ?array $headers = null)
{
$this->request = $request;
$this->query = $query;
@@ -140,11 +140,10 @@ class Response implements ResponseInterface
}
/**
* @param int $statusCode
* @param string $text
* @throws InvalidArgumentException
*/
public function setStatusCode($statusCode, $text = null)
public function setStatusCode(int $statusCode, $text = null)
{
$this->statusCode = (int) $statusCode;
if ($this->isInvalid()) {
@@ -20,10 +20,7 @@ interface ResponseInterface
*/
public function addHttpHeaders(array $httpHeaders);
/**
* @param int $statusCode
*/
public function setStatusCode($statusCode);
public function setStatusCode(int $statusCode);
/**
* @param int $statusCode
@@ -38,7 +38,7 @@ class AccessToken implements AccessTokenInterface
* );
* @endcode
*/
public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array())
public function __construct(AccessTokenStorageInterface $tokenStorage, ?RefreshTokenInterface $refreshStorage = null, array $config = array())
{
$this->tokenStorage = $tokenStorage;
$this->refreshStorage = $refreshStorage;
@@ -26,9 +26,9 @@ class AuthorizationCode implements AuthorizationCodeInterface
// build the URL to redirect to
$result = array('query' => array());
$params += array('scope' => null, 'state' => null);
$params += array('scope' => null, 'state' => null, 'code_challenge' => null, 'code_challenge_method' => null);
$result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope']);
$result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope'], $params['code_challenge'], $params['code_challenge_method']);
if (isset($params['state'])) {
$result['query']['state'] = $params['state'];
@@ -53,10 +53,10 @@ class AuthorizationCode implements AuthorizationCodeInterface
* @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4
*/
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null)
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $code_challenge = null, $code_challenge_method = null)
{
$code = $this->generateAuthorizationCode();
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope);
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope, null, $code_challenge, $code_challenge_method);
return $code;
}
@@ -26,7 +26,7 @@ class JwtAccessToken extends AccessToken
* or just the token ID is stored
* @param EncryptionInterface $encryptionUtil -
*/
public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
public function __construct(?PublicKeyInterface $publicKeyStorage = null, ?AccessTokenStorageInterface $tokenStorage = null, ?RefreshTokenInterface $refreshStorage = null, array $config = array(), ?EncryptionInterface $encryptionUtil = null)
{
$this->publicKeyStorage = $publicKeyStorage;
$config = array_merge(array(
@@ -150,7 +150,7 @@ class Server implements ResourceControllerInterface,
*
* @ingroup oauth2_section_7
*/
public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), TokenTypeInterface $tokenType = null, ScopeInterface $scopeUtil = null, ClientAssertionTypeInterface $clientAssertionType = null)
public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), ?TokenTypeInterface $tokenType = null, ?ScopeInterface $scopeUtil = null, ?ClientAssertionTypeInterface $clientAssertionType = null)
{
$storage = is_array($storage) ? $storage : array($storage);
$this->storages = array();
@@ -172,6 +172,7 @@ class Server implements ResourceControllerInterface,
'enforce_state' => true,
'require_exact_redirect_uri' => true,
'allow_implicit' => false,
'enforce_pkce' => false,
'allow_credentials_in_request_body' => true,
'allow_public_clients' => true,
'always_issue_new_refresh_token' => false,
@@ -288,7 +289,7 @@ class Server implements ResourceControllerInterface,
*
* @see http://openid.net/specs/openid-connect-core-1_0.html#UserInfo
*/
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response = null)
public function handleUserInfoRequest(RequestInterface $request, ?ResponseInterface $response = null)
{
$this->response = is_null($response) ? new Response() : $response;
$this->getUserInfoController()->handleUserInfoRequest($request, $this->response);
@@ -314,7 +315,7 @@ class Server implements ResourceControllerInterface,
*
* @ingroup oauth2_section_4
*/
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response = null)
public function handleTokenRequest(RequestInterface $request, ?ResponseInterface $response = null)
{
$this->response = is_null($response) ? new Response() : $response;
$this->getTokenController()->handleTokenRequest($request, $this->response);
@@ -327,7 +328,7 @@ class Server implements ResourceControllerInterface,
* @param ResponseInterface $response - Response object
* @return mixed
*/
public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null)
public function grantAccessToken(RequestInterface $request, ?ResponseInterface $response = null)
{
$this->response = is_null($response) ? new Response() : $response;
$value = $this->getTokenController()->grantAccessToken($request, $this->response);
@@ -345,7 +346,7 @@ class Server implements ResourceControllerInterface,
* @param ResponseInterface $response
* @return Response|ResponseInterface
*/
public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response = null)
public function handleRevokeRequest(RequestInterface $request, ?ResponseInterface $response = null)
{
$this->response = is_null($response) ? new Response() : $response;
$this->getTokenController()->handleRevokeRequest($request, $this->response);
@@ -407,7 +408,7 @@ class Server implements ResourceControllerInterface,
*
* @ingroup oauth2_section_3
*/
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response = null)
public function validateAuthorizeRequest(RequestInterface $request, ?ResponseInterface $response = null)
{
$this->response = is_null($response) ? new Response() : $response;
$value = $this->getAuthorizeController()->validateAuthorizeRequest($request, $this->response);
@@ -421,7 +422,7 @@ class Server implements ResourceControllerInterface,
* @param string $scope - Scope
* @return mixed
*/
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null)
public function verifyResourceRequest(RequestInterface $request, ?ResponseInterface $response = null, $scope = null)
{
$this->response = is_null($response) ? new Response() : $response;
$value = $this->getResourceController()->verifyResourceRequest($request, $this->response, $scope);
@@ -434,7 +435,7 @@ class Server implements ResourceControllerInterface,
* @param ResponseInterface $response - Response object
* @return mixed
*/
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null)
public function getAccessTokenData(RequestInterface $request, ?ResponseInterface $response = null)
{
$this->response = is_null($response) ? new Response() : $response;
$value = $this->getResourceController()->getAccessTokenData($request, $this->response);
@@ -577,7 +578,7 @@ class Server implements ResourceControllerInterface,
}
}
$config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_implicit enforce_state require_exact_redirect_uri')));
$config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_implicit enforce_state require_exact_redirect_uri enforce_pkce')));
if ($this->config['use_openid_connect']) {
return new OpenIDAuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil());
@@ -191,11 +191,11 @@ class Cassandra implements AuthorizationCodeInterface,
* @param string $id_token
* @return bool
*/
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
return $this->setValue(
$this->config['code_key'] . $authorization_code,
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'),
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token', 'code_challenge', 'code_challenge_method'),
$expires
);
}
@@ -2,6 +2,7 @@
namespace OAuth2\Storage;
use Couchbase;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
/**
@@ -27,14 +28,18 @@ class CouchbaseDB implements AuthorizationCodeInterface,
public function __construct($connection, $config = array())
{
if ($connection instanceof \Couchbase) {
if (!class_exists(Couchbase::class)) {
throw new \RuntimeException('Missing Couchbase');
}
if ($connection instanceof Couchbase) {
$this->db = $connection;
} else {
if (!is_array($connection) || !is_array($connection['servers'])) {
throw new \InvalidArgumentException('First argument to OAuth2\Storage\CouchbaseDB must be an instance of Couchbase or a configuration array containing a server array');
}
$this->db = new \Couchbase($connection['servers'], (!isset($connection['username'])) ? '' : $connection['username'], (!isset($connection['password'])) ? '' : $connection['password'], $connection['bucket'], false);
$this->db = new Couchbase($connection['servers'], (!isset($connection['username'])) ? '' : $connection['username'], (!isset($connection['password'])) ? '' : $connection['password'], $connection['bucket'], false);
}
$this->config = array_merge(array(
@@ -173,7 +178,7 @@ class CouchbaseDB implements AuthorizationCodeInterface,
return is_null($code) ? false : $code;
}
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
// if it exists, update it.
if ($this->getAuthorizationCode($code)) {
@@ -185,6 +190,8 @@ class CouchbaseDB implements AuthorizationCodeInterface,
'expires' => $expires,
'scope' => $scope,
'id_token' => $id_token,
'code_challenge' => $code_challenge,
'code_challenge_method' => $code_challenge_method,
));
} else {
$this->setObjectByType('code_table',$code,array(
@@ -195,6 +202,8 @@ class CouchbaseDB implements AuthorizationCodeInterface,
'expires' => $expires,
'scope' => $scope,
'id_token' => $id_token,
'code_challenge' => $code_challenge,
'code_challenge_method' => $code_challenge_method,
));
}
@@ -328,4 +337,4 @@ class CouchbaseDB implements AuthorizationCodeInterface,
//TODO: Needs couchbase implementation.
throw new \Exception('setJti() for the Couchbase driver is currently unimplemented.');
}
}
}
@@ -213,12 +213,12 @@ class DynamoDB implements
}
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
// convert expires to datestring
$expires = date('Y-m-d H:i:s', $expires);
$clientData = compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'id_token', 'scope');
$clientData = compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token', 'code_challenge', 'code_challenge_method');
$clientData = array_filter($clientData, 'self::isNotEmpty');
$result = $this->client->putItem(array(
@@ -21,7 +21,7 @@ class JwtAccessToken implements JwtAccessTokenInterface
* is not necessary when using this grant type.
* @param OAuth2\Encryption\EncryptionInterface $encryptionUtil OPTIONAL class to use for "encode" and "decode" functions.
*/
public function __construct(PublicKeyInterface $publicKeyStorage, AccessTokenInterface $tokenStorage = null, EncryptionInterface $encryptionUtil = null)
public function __construct(PublicKeyInterface $publicKeyStorage, ?AccessTokenInterface $tokenStorage = null, ?EncryptionInterface $encryptionUtil = null)
{
$this->publicKeyStorage = $publicKeyStorage;
$this->tokenStorage = $tokenStorage;
@@ -84,4 +84,4 @@ class JwtAccessToken implements JwtAccessTokenInterface
return $tokenData;
}
}
}
@@ -74,9 +74,9 @@ class Memory implements AuthorizationCodeInterface,
), $this->authorizationCodes[$code]);
}
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
$this->authorizationCodes[$code] = compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token');
$this->authorizationCodes[$code] = compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token', 'code_challenge', 'code_challenge_method');
return true;
}
@@ -179,7 +179,7 @@ class Mongo implements AuthorizationCodeInterface,
return is_null($code) ? false : $code;
}
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
// if it exists, update it.
if ($this->getAuthorizationCode($code)) {
@@ -192,6 +192,8 @@ class Mongo implements AuthorizationCodeInterface,
'expires' => $expires,
'scope' => $scope,
'id_token' => $id_token,
'code_challenge' => $code_challenge,
'code_challenge_method' => $code_challenge_method,
))
);
} else {
@@ -203,6 +205,8 @@ class Mongo implements AuthorizationCodeInterface,
'expires' => $expires,
'scope' => $scope,
'id_token' => $id_token,
'code_challenge' => $code_challenge,
'code_challenge_method' => $code_challenge_method,
);
$this->collection('code_table')->insert($token);
}
@@ -32,6 +32,9 @@ class MongoDB implements AuthorizationCodeInterface,
public function __construct($connection, $config = array())
{
if (!class_exists(Database::class) || !class_exists(Client::class)) {
throw new \LogicException('Missing MongoDB php extension. Please install mongodb.so');
}
if ($connection instanceof Database) {
$this->db = $connection;
} else {
@@ -167,7 +170,7 @@ class MongoDB implements AuthorizationCodeInterface,
return is_null($code) ? false : $code;
}
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
// if it exists, update it.
if ($this->getAuthorizationCode($code)) {
@@ -180,6 +183,8 @@ class MongoDB implements AuthorizationCodeInterface,
'expires' => $expires,
'scope' => $scope,
'id_token' => $id_token,
'code_challenge' => $code_challenge,
'code_challenge_method' => $code_challenge_method,
))
);
return $result->getMatchedCount() > 0;
@@ -192,6 +197,8 @@ class MongoDB implements AuthorizationCodeInterface,
'expires' => $expires,
'scope' => $scope,
'id_token' => $id_token,
'code_challenge' => $code_challenge,
'code_challenge_method' => $code_challenge_method,
);
$result = $this->collection('code_table')->insertOne($token);
return $result->getInsertedCount() > 0;
@@ -247,7 +247,7 @@ class Pdo implements
* @param string $id_token
* @return bool|mixed
*/
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
if (func_num_args() > 6) {
// we are calling with an id token
@@ -259,12 +259,12 @@ class Pdo implements
// if it exists, update it.
if ($this->getAuthorizationCode($code)) {
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope where authorization_code=:code', $this->config['code_table']));
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope, code_challenge=:code_challenge, code_challenge_method=:code_challenge_method where authorization_code=:code', $this->config['code_table']));
} else {
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)', $this->config['code_table']));
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope, code_challenge, code_challenge_method) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope, :code_challenge, :code_challenge_method)', $this->config['code_table']));
}
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope'));
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'code_challenge', 'code_challenge_method'));
}
/**
@@ -277,19 +277,19 @@ class Pdo implements
* @param string $id_token
* @return bool
*/
private function setAuthorizationCodeWithIdToken($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
private function setAuthorizationCodeWithIdToken($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
// convert expires to datestring
$expires = date('Y-m-d H:i:s', $expires);
// if it exists, update it.
if ($this->getAuthorizationCode($code)) {
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope, id_token =:id_token where authorization_code=:code', $this->config['code_table']));
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope, id_token =:id_token, code_challenge=:code_challenge, code_challenge_method=:code_challenge_method where authorization_code=:code', $this->config['code_table']));
} else {
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope, id_token) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope, :id_token)', $this->config['code_table']));
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope, id_token, code_challenge, code_challenge_method) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope, :id_token, :code_challenge, :code_challenge_method)', $this->config['code_table']));
}
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'));
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token', 'code_challenge', 'code_challenge_method'));
}
/**
@@ -676,6 +676,8 @@ class Pdo implements
expires TIMESTAMP NOT NULL,
scope VARCHAR(4000),
id_token VARCHAR(1000),
code_challenge VARCHAR(1000),
code_challenge_method VARCHAR(20),
PRIMARY KEY (authorization_code)
);
@@ -95,11 +95,11 @@ class Redis implements AuthorizationCodeInterface,
return $this->getValue($this->config['code_key'] . $code);
}
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null, $code_challenge = null, $code_challenge_method = null)
{
return $this->setValue(
$this->config['code_key'] . $authorization_code,
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'),
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token', 'code_challenge', 'code_challenge_method'),
$expires
);
}
@@ -109,7 +109,7 @@ class Bearer implements TokenTypeInterface
}
$contentType = $request->server('CONTENT_TYPE');
if (false !== $pos = strpos($contentType, ';')) {
if (false !== $pos = strpos((string) $contentType, ';')) {
$contentType = substr($contentType, 0, $pos);
}
@@ -133,7 +133,7 @@ class AuthorizeControllerTest extends TestCase
$server->handleAuthorizeRequest($request, $response = new Response(), true);
$this->assertEquals($response->getStatusCode(), 302);
$this->assertNotContains('error', $response->getHttpHeader('Location'));
$this->assertStringNotContainsString('error', $response->getHttpHeader('Location'));
}
public function testEnforceScope()
@@ -161,7 +161,7 @@ class AuthorizeControllerTest extends TestCase
$server->handleAuthorizeRequest($request, $response = new Response(), true);
$this->assertEquals($response->getStatusCode(), 302);
$this->assertNotContains('error', $response->getHttpHeader('Location'));
$this->assertStringNotContainsString('error', $response->getHttpHeader('Location'));
}
public function testInvalidRedirectUri()
@@ -227,7 +227,7 @@ class AuthorizeControllerTest extends TestCase
$server->handleAuthorizeRequest($request, $response = new Response(), true);
$this->assertEquals($response->getStatusCode(), 302);
$this->assertContains('code', $response->getHttpHeader('Location'));
$this->assertStringContainsString('code', $response->getHttpHeader('Location'));
}
public function testRedirectUriWithDifferentQueryAndExactMatchRequired()
@@ -263,7 +263,7 @@ class AuthorizeControllerTest extends TestCase
$server->handleAuthorizeRequest($request, $response = new Response(), true);
$this->assertEquals($response->getStatusCode(), 302);
$this->assertContains('code', $response->getHttpHeader('Location'));
$this->assertStringContainsString('code', $response->getHttpHeader('Location'));
}
public function testMultipleRedirectUris()
@@ -278,14 +278,14 @@ class AuthorizeControllerTest extends TestCase
$server->handleAuthorizeRequest($request, $response = new Response(), true);
$this->assertEquals($response->getStatusCode(), 302);
$this->assertContains('code', $response->getHttpHeader('Location'));
$this->assertStringContainsString('code', $response->getHttpHeader('Location'));
// call again with different (but still valid) redirect URI
$request->query['redirect_uri'] = 'http://morehazards.com';
$server->handleAuthorizeRequest($request, $response = new Response(), true);
$this->assertEquals($response->getStatusCode(), 302);
$this->assertContains('code', $response->getHttpHeader('Location'));
$this->assertStringContainsString('code', $response->getHttpHeader('Location'));
}
/**
@@ -303,7 +303,7 @@ class AuthorizeControllerTest extends TestCase
$server->handleAuthorizeRequest($request, $response = new Response(), true);
$this->assertEquals($response->getStatusCode(), 302);
$this->assertContains('state', $response->getHttpHeader('Location'));
$this->assertStringContainsString('state', $response->getHttpHeader('Location'));
$this->assertStringStartsWith('http://brentertainment.com?code=', $response->getHttpHeader('Location'));
$parts = parse_url($response->getHttpHeader('Location'));
@@ -421,7 +421,7 @@ class AuthorizeControllerTest extends TestCase
$this->assertEquals($response->getStatusCode(), 302);
$location = $response->getHttpHeader('Location');
$this->assertNotContains('error', $location);
$this->assertStringNotContainsString('error', $location);
$parts = parse_url($location);
$this->assertFalse(isset($parts['fake']));
@@ -9,7 +9,7 @@ class FirebaseJwtTest extends TestCase
{
private $privateKey;
public function setUp()
public function setUp(): void
{
$this->privateKey = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
@@ -9,7 +9,7 @@ class JwtTest extends TestCase
{
private $privateKey;
public function setUp()
public function setUp(): void
{
$this->privateKey = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
@@ -13,7 +13,7 @@ class JwtBearerTest extends TestCase
{
private $privateKey;
public function setUp()
public function setUp(): void
{
$this->privateKey = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
@@ -29,7 +29,7 @@ class CodeIdTokenTest extends TestCase
$this->assertEquals($response->getStatusCode(), 302);
$location = $response->getHttpHeader('Location');
$this->assertNotContains('error', $location);
$this->assertStringNotContainsString('error', $location);
$parts = parse_url($location);
$this->assertArrayHasKey('query', $parts);
@@ -87,7 +87,7 @@ class CodeIdTokenTest extends TestCase
$this->assertEquals($response->getStatusCode(), 302);
$location = $response->getHttpHeader('Location');
$this->assertNotContains('error', $location);
$this->assertStringNotContainsString('error', $location);
$parts = parse_url($location);
$this->assertArrayHasKey('query', $parts);
@@ -133,7 +133,7 @@ class CodeIdTokenTest extends TestCase
$this->assertEquals($response->getStatusCode(), 302);
$location = $response->getHttpHeader('Location');
$this->assertNotContains('error', $location);
$this->assertStringNotContainsString('error', $location);
$parts = parse_url($location);
$this->assertArrayHasKey('query', $parts);
@@ -52,7 +52,7 @@ class IdTokenTest extends TestCase
$this->assertEquals($response->getStatusCode(), 302);
$location = $response->getHttpHeader('Location');
$this->assertNotContains('error', $location);
$this->assertStringNotContainsString('error', $location);
$parts = parse_url($location);
$this->assertArrayHasKey('fragment', $parts);
@@ -110,7 +110,7 @@ class IdTokenTest extends TestCase
{
$this->assertEquals($response->getStatusCode(), 302);
$location = $response->getHttpHeader('Location');
$this->assertNotContains('error', $location);
$this->assertStringNotContainsString('error', $location);
$parts = parse_url($location);
$this->assertArrayHasKey('fragment', $parts);
@@ -31,7 +31,7 @@ class IdTokenTokenTest extends TestCase
$this->assertEquals($response->getStatusCode(), 302);
$location = $response->getHttpHeader('Location');
$this->assertNotContains('error', $location);
$this->assertStringNotContainsString('error', $location);
$parts = parse_url($location);
$this->assertArrayHasKey('fragment', $parts);
@@ -14,7 +14,7 @@ class ResponseTest extends TestCase
));
$string = $response->getResponseBody('xml');
$this->assertContains('<response><foo>bar</foo><halland>oates</halland></response>', $string);
$this->assertStringContainsString('<response><foo>bar</foo><halland>oates</halland></response>', $string);
}
public function testSetRedirect()
@@ -40,20 +40,20 @@ class JwtAccessTokenTest extends TestCase
$this->assertEquals(3600, $delta);
$this->assertEquals($decodedAccessToken['id'], $decodedAccessToken['jti']);
}
public function testExtraPayloadCallback()
{
$jwtconfig = array('jwt_extra_payload_callable' => function() {
return array('custom_param' => 'custom_value');
});
$server = $this->getTestServer($jwtconfig);
$jwtResponseType = $server->getResponseType('token');
$accessToken = $jwtResponseType->createAccessToken('Test Client ID', 123, 'test', false);
$jwt = new Jwt;
$decodedAccessToken = $jwt->decode($accessToken['access_token'], null, false);
$this->assertArrayHasKey('custom_param', $decodedAccessToken);
$this->assertEquals('custom_value', $decodedAccessToken['custom_param']);
}
@@ -162,7 +162,7 @@ class JwtAccessTokenTest extends TestCase
$memoryStorage = Bootstrap::getInstance()->getMemoryStorage();
$storage = array(
'access_token' => new JwtAccessTokenStorage($memoryStorage),
'access_token' => new JwtAccessTokenStorage($memoryStorage, $memoryStorage),
'client' => $memoryStorage,
'client_credentials' => $memoryStorage,
);
@@ -6,27 +6,26 @@ use OAuth2\Request\TestRequest;
use OAuth2\ResponseType\AuthorizationCode;
use OAuth2\Storage\Bootstrap;
use PHPUnit\Framework\TestCase;
use Yoast\PHPUnitPolyfills\Polyfills\ExpectPHPException;
class ServerTest extends TestCase
{
/**
* @expectedException LogicException OAuth2\Storage\ClientInterface
**/
use ExpectPHPException;
public function testGetAuthorizeControllerWithNoClientStorageThrowsException()
{
$this->expectExceptionMessage('OAuth2\Storage\ClientInterface');
// must set Client Storage
$server = new Server();
$server->getAuthorizeController();
}
/**
* @expectedException LogicException OAuth2\Storage\AccessTokenInterface
**/
public function testGetAuthorizeControllerWithNoAccessTokenStorageThrowsException()
{
$this->expectExceptionMessage('OAuth2\Storage\AccessTokenInterface');
// must set AccessToken or AuthorizationCode
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientInterface'));
$server->getAuthorizeController();
}
@@ -34,8 +33,8 @@ class ServerTest extends TestCase
{
// must set AccessToken or AuthorizationCode
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
$server->addResponseType($this->getMock('OAuth2\ResponseType\AccessTokenInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientInterface'));
$server->addResponseType($this->createMock('OAuth2\ResponseType\AccessTokenInterface'));
$this->assertNotNull($server->getAuthorizeController());
}
@@ -44,21 +43,19 @@ class ServerTest extends TestCase
{
// must set AccessToken or AuthorizationCode
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
$server->addResponseType($this->getMock('OAuth2\ResponseType\AuthorizationCodeInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientInterface'));
$server->addResponseType($this->createMock('OAuth2\ResponseType\AuthorizationCodeInterface'));
$this->assertNotNull($server->getAuthorizeController());
}
/**
* @expectedException LogicException allow_implicit
**/
public function testGetAuthorizeControllerWithClientStorageAndAccessTokenStorageThrowsException()
{
// must set AuthorizationCode or AccessToken / implicit
$this->expectExceptionMessage('allow_implicit');
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
$server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'));
$this->assertNotNull($server->getAuthorizeController());
}
@@ -67,8 +64,8 @@ class ServerTest extends TestCase
{
// must set AuthorizationCode or AccessToken / implicit
$server = new Server(array(), array('allow_implicit' => true));
$server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
$server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'));
$this->assertNotNull($server->getAuthorizeController());
}
@@ -77,63 +74,55 @@ class ServerTest extends TestCase
{
// must set AccessToken or AuthorizationCode
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\ClientInterface'));
$server->addStorage($this->getMock('OAuth2\Storage\AuthorizationCodeInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\AuthorizationCodeInterface'));
$this->assertNotNull($server->getAuthorizeController());
}
/**
* @expectedException LogicException grant_types
**/
public function testGetTokenControllerWithGrantTypeStorageThrowsException()
{
$this->expectExceptionMessage('grant_types');
$server = new Server();
$server->getTokenController();
}
/**
* @expectedException LogicException OAuth2\Storage\ClientCredentialsInterface
**/
public function testGetTokenControllerWithNoClientCredentialsStorageThrowsException()
{
$this->expectExceptionMessage('OAuth2\Storage\ClientCredentialsInterface');
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\UserCredentialsInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\UserCredentialsInterface'));
$server->getTokenController();
}
/**
* @expectedException LogicException OAuth2\Storage\AccessTokenInterface
**/
public function testGetTokenControllerWithNoAccessTokenStorageThrowsException()
{
$this->expectExceptionMessage('OAuth2\Storage\AccessTokenInterface');
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->getTokenController();
}
public function testGetTokenControllerWithAccessTokenAndClientCredentialsStorage()
{
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
$server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->getTokenController();
}
public function testGetTokenControllerAccessTokenStorageAndClientCredentialsStorageAndGrantTypes()
{
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
$server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->addGrantType($this->getMockBuilder('OAuth2\GrantType\AuthorizationCode')->disableOriginalConstructor()->getMock());
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->addGrantType($this->createMock('OAuth2\GrantType\AuthorizationCode'));
$server->getTokenController();
}
/**
* @expectedException LogicException OAuth2\Storage\AccessTokenInterface
**/
public function testGetResourceControllerWithNoAccessTokenStorageThrowsException()
{
$this->expectExceptionMessage('OAuth2\Storage\AccessTokenInterface');
$server = new Server();
$server->getResourceController();
}
@@ -141,41 +130,35 @@ class ServerTest extends TestCase
public function testGetResourceControllerWithAccessTokenStorage()
{
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'));
$server->getResourceController();
}
/**
* @expectedException InvalidArgumentException OAuth2\Storage\AccessTokenInterface
**/
public function testAddingStorageWithInvalidClass()
{
$this->expectExceptionMessage('OAuth2\Storage\AccessTokenInterface');
$server = new Server();
$server->addStorage(new \StdClass());
}
/**
* @expectedException InvalidArgumentException access_token
**/
public function testAddingStorageWithInvalidKey()
{
$this->expectExceptionMessage('access_token');
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'), 'nonexistant_storage');
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'), 'nonexistant_storage');
}
/**
* @expectedException InvalidArgumentException OAuth2\Storage\AuthorizationCodeInterface
**/
public function testAddingStorageWithInvalidKeyStorageCombination()
{
$this->expectExceptionMessage('OAuth2\Storage\AuthorizationCodeInterface');
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'), 'authorization_code');
$server->addStorage($this->createMock('OAuth2\Storage\AccessTokenInterface'), 'authorization_code');
}
public function testAddingStorageWithValidKeyOnlySetsThatKey()
{
$server = new Server();
$server->addStorage($this->getMock('OAuth2\Storage\Memory'), 'access_token');
$server->addStorage($this->createMock('OAuth2\Storage\Memory'), 'access_token');
$reflection = new \ReflectionClass($server);
$prop = $reflection->getProperty('storages');
@@ -191,7 +174,7 @@ class ServerTest extends TestCase
public function testAddingClientStorageSetsClientCredentialsStorageByDefault()
{
$server = new Server();
$memory = $this->getMock('OAuth2\Storage\Memory');
$memory = $this->createMock('OAuth2\Storage\Memory');
$server->addStorage($memory, 'client');
$client_credentials = $server->getStorage('client_credentials');
@@ -202,7 +185,7 @@ class ServerTest extends TestCase
public function testAddStorageWithNullValue()
{
$memory = $this->getMock('OAuth2\Storage\Memory');
$memory = $this->createMock('OAuth2\Storage\Memory');
$server = new Server($memory);
$server->addStorage(null, 'refresh_token');
@@ -218,7 +201,7 @@ class ServerTest extends TestCase
public function testNewServerWithNullStorageValue()
{
$memory = $this->getMock('OAuth2\Storage\Memory');
$memory = $this->createMock('OAuth2\Storage\Memory');
$server = new Server(array(
'client_credentials' => $memory,
'refresh_token' => null,
@@ -237,7 +220,7 @@ class ServerTest extends TestCase
public function testAddingClientCredentialsStorageSetsClientStorageByDefault()
{
$server = new Server();
$memory = $this->getMock('OAuth2\Storage\Memory');
$memory = $this->createMock('OAuth2\Storage\Memory');
$server->addStorage($memory, 'client_credentials');
$client = $server->getStorage('client');
@@ -249,10 +232,9 @@ class ServerTest extends TestCase
public function testSettingClientStorageByDefaultDoesNotOverrideSetStorage()
{
$server = new Server();
$pdo = $this->getMockBuilder('OAuth2\Storage\Pdo')
->disableOriginalConstructor()->getMock();
$pdo = $this->createMock('OAuth2\Storage\Pdo');
$memory = $this->getMock('OAuth2\Storage\Memory');
$memory = $this->createMock('OAuth2\Storage\Memory');
$server->addStorage($pdo, 'client');
$server->addStorage($memory, 'client_credentials');
@@ -266,7 +248,7 @@ class ServerTest extends TestCase
public function testAddingResponseType()
{
$storage = $this->getMock('OAuth2\Storage\Memory');
$storage = $this->createMock('OAuth2\Storage\Memory');
$storage
->expects($this->any())
->method('getClientDetails')
@@ -323,7 +305,7 @@ class ServerTest extends TestCase
'code' => 'testcode',
));
// verify the mock clientAssertionType was called as expected
$clientAssertionType = $this->getMock('OAuth2\ClientAssertionType\ClientAssertionTypeInterface', array('validateRequest', 'getClientId'));
$clientAssertionType = $this->createMock('OAuth2\ClientAssertionType\ClientAssertionTypeInterface');
$clientAssertionType
->expects($this->once())
->method('validateRequest')
@@ -420,98 +402,84 @@ class ServerTest extends TestCase
$this->assertFalse($used_token, 'the refresh token used is no longer valid');
}
/**
* @expectedException InvalidArgumentException OAuth2\ResponseType\AuthorizationCodeInterface
**/
public function testAddingUnknownResponseTypeThrowsException()
{
$this->expectExceptionMessage('OAuth2\ResponseType\AuthorizationCodeInterface');
$server = new Server();
$server->addResponseType($this->getMock('OAuth2\ResponseType\ResponseTypeInterface'));
$server->addResponseType($this->createMock('OAuth2\ResponseType\ResponseTypeInterface'));
}
/**
* @expectedException LogicException OAuth2\Storage\PublicKeyInterface
**/
public function testUsingJwtAccessTokensWithoutPublicKeyStorageThrowsException()
{
$this->expectExceptionMessage('OAuth2\Storage\PublicKeyInterface');
$server = new Server(array(), array('use_jwt_access_tokens' => true));
$server->addGrantType($this->getMock('OAuth2\GrantType\GrantTypeInterface'));
$server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->addGrantType($this->createMock('OAuth2\GrantType\GrantTypeInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->addStorage($this->createMock('OAuth2\Storage\ClientCredentialsInterface'));
$server->getTokenController();
}
public function testUsingJustJwtAccessTokenStorageWithResourceControllerIsOkay()
{
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$server = new Server(array($pubkey), array('use_jwt_access_tokens' => true));
$this->assertNotNull($server->getResourceController());
$this->assertInstanceOf('OAuth2\Storage\PublicKeyInterface', $server->getStorage('public_key'));
}
/**
* @expectedException LogicException OAuth2\Storage\ClientInterface
**/
public function testUsingJustJwtAccessTokenStorageWithAuthorizeControllerThrowsException()
{
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$this->expectExceptionMessage('OAuth2\Storage\ClientInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$server = new Server(array($pubkey), array('use_jwt_access_tokens' => true));
$this->assertNotNull($server->getAuthorizeController());
}
/**
* @expectedException LogicException grant_types
**/
public function testUsingJustJwtAccessTokenStorageWithTokenControllerThrowsException()
{
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$this->expectExceptionMessage('grant_types');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$server = new Server(array($pubkey), array('use_jwt_access_tokens' => true));
$server->getTokenController();
}
public function testUsingJwtAccessTokenAndClientStorageWithAuthorizeControllerIsOkay()
{
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$client = $this->getMock('OAuth2\Storage\ClientInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$server = new Server(array($pubkey, $client), array('use_jwt_access_tokens' => true, 'allow_implicit' => true));
$this->assertNotNull($server->getAuthorizeController());
$this->assertInstanceOf('OAuth2\ResponseType\JwtAccessToken', $server->getResponseType('token'));
}
/**
* @expectedException LogicException UserClaims
**/
public function testUsingOpenIDConnectWithoutUserClaimsThrowsException()
{
$client = $this->getMock('OAuth2\Storage\ClientInterface');
$this->expectExceptionMessage('UserClaims');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$server = new Server($client, array('use_openid_connect' => true));
$server->getAuthorizeController();
}
/**
* @expectedException LogicException PublicKeyInterface
**/
public function testUsingOpenIDConnectWithoutPublicKeyThrowsException()
{
$client = $this->getMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->getMock('OAuth2\OPenID\Storage\UserClaimsInterface');
$this->expectExceptionMessage('PublicKeyInterface');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->createMock('OAuth2\OPenID\Storage\UserClaimsInterface');
$server = new Server(array($client, $userclaims), array('use_openid_connect' => true));
$server->getAuthorizeController();
}
/**
* @expectedException LogicException issuer
**/
public function testUsingOpenIDConnectWithoutIssuerThrowsException()
{
$client = $this->getMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$this->expectExceptionMessage('issuer');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->createMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$server = new Server(array($client, $userclaims, $pubkey), array('use_openid_connect' => true));
$server->getAuthorizeController();
@@ -519,9 +487,9 @@ class ServerTest extends TestCase
public function testUsingOpenIDConnectWithIssuerPublicKeyAndUserClaimsIsOkay()
{
$client = $this->getMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->createMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$server = new Server(array($client, $userclaims, $pubkey), array(
'use_openid_connect' => true,
'issuer' => 'someguy',
@@ -533,14 +501,12 @@ class ServerTest extends TestCase
$this->assertNull($server->getResponseType('id_token token'));
}
/**
* @expectedException LogicException OAuth2\ResponseType\AccessTokenInterface
**/
public function testUsingOpenIDConnectWithAllowImplicitWithoutTokenStorageThrowsException()
{
$client = $this->getMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$this->expectErrorMessage('OAuth2\ResponseType\AccessTokenInterface');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->createMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$server = new Server(array($client, $userclaims, $pubkey), array(
'use_openid_connect' => true,
'issuer' => 'someguy',
@@ -552,9 +518,9 @@ class ServerTest extends TestCase
public function testUsingOpenIDConnectWithAllowImplicitAndUseJwtAccessTokensIsOkay()
{
$client = $this->getMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->createMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$server = new Server(array($client, $userclaims, $pubkey), array(
'use_openid_connect' => true,
'issuer' => 'someguy',
@@ -570,10 +536,10 @@ class ServerTest extends TestCase
public function testUsingOpenIDConnectWithAllowImplicitAndAccessTokenStorageIsOkay()
{
$client = $this->getMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$token = $this->getMock('OAuth2\Storage\AccessTokenInterface');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->createMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$token = $this->createMock('OAuth2\Storage\AccessTokenInterface');
$server = new Server(array($client, $userclaims, $pubkey, $token), array(
'use_openid_connect' => true,
'issuer' => 'someguy',
@@ -588,17 +554,17 @@ class ServerTest extends TestCase
public function testUsingOpenIDConnectWithAllowImplicitAndAccessTokenResponseTypeIsOkay()
{
$client = $this->getMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
// $token = $this->getMock('OAuth2\Storage\AccessTokenInterface');
$client = $this->createMock('OAuth2\Storage\ClientInterface');
$userclaims = $this->createMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
// $token = $this->createMock('OAuth2\Storage\AccessTokenInterface');
$server = new Server(array($client, $userclaims, $pubkey), array(
'use_openid_connect' => true,
'issuer' => 'someguy',
'allow_implicit' => true,
));
$token = $this->getMock('OAuth2\ResponseType\AccessTokenInterface');
$token = $this->createMock('OAuth2\ResponseType\AccessTokenInterface');
$server->addResponseType($token, 'token');
$server->getAuthorizeController();
@@ -607,17 +573,15 @@ class ServerTest extends TestCase
$this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token'));
}
/**
* @expectedException LogicException OAuth2\OpenID\Storage\AuthorizationCodeInterface
**/
public function testUsingOpenIDConnectWithAuthorizationCodeStorageThrowsException()
{
$client = $this->getMock('OAuth2\Storage\ClientCredentialsInterface');
$userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$token = $this->getMock('OAuth2\Storage\AccessTokenInterface');
$authcode = $this->getMock('OAuth2\Storage\AuthorizationCodeInterface');
$client = $this->createMock('OAuth2\Storage\ClientCredentialsInterface');
$userclaims = $this->createMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$token = $this->createMock('OAuth2\Storage\AccessTokenInterface');
$authcode = $this->createMock('OAuth2\Storage\AuthorizationCodeInterface');
$this->expectErrorMessage('OAuth2\OpenID\Storage\AuthorizationCodeInterface');
$server = new Server(array($client, $userclaims, $pubkey, $token, $authcode), array(
'use_openid_connect' => true,
'issuer' => 'someguy'
@@ -630,11 +594,11 @@ class ServerTest extends TestCase
public function testUsingOpenIDConnectWithOpenIDAuthorizationCodeStorageCreatesOpenIDAuthorizationCodeGrantType()
{
$client = $this->getMock('OAuth2\Storage\ClientCredentialsInterface');
$userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface');
$token = $this->getMock('OAuth2\Storage\AccessTokenInterface');
$authcode = $this->getMock('OAuth2\OpenID\Storage\AuthorizationCodeInterface');
$client = $this->createMock('OAuth2\Storage\ClientCredentialsInterface');
$userclaims = $this->createMock('OAuth2\OpenID\Storage\UserClaimsInterface');
$pubkey = $this->createMock('OAuth2\Storage\PublicKeyInterface');
$token = $this->createMock('OAuth2\Storage\AccessTokenInterface');
$authcode = $this->createMock('OAuth2\OpenID\Storage\AuthorizationCodeInterface');
$server = new Server(array($client, $userclaims, $pubkey, $token, $authcode), array(
'use_openid_connect' => true,
@@ -648,7 +612,7 @@ class ServerTest extends TestCase
public function testMultipleValuedResponseTypeOrderDoesntMatter()
{
$responseType = $this->getMock('OAuth2\OpenID\ResponseType\IdTokenTokenInterface');
$responseType = $this->createMock('OAuth2\OpenID\ResponseType\IdTokenTokenInterface');
$server = new Server(array(), array(), array(), array(
'token id_token' => $responseType,
));
@@ -659,7 +623,7 @@ class ServerTest extends TestCase
public function testAddGrantTypeWithoutKey()
{
$server = new Server();
$server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')));
$server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->createMock('OAuth2\Storage\AuthorizationCodeInterface')));
$grantTypes = $server->getGrantTypes();
$this->assertEquals('authorization_code', key($grantTypes));
@@ -668,7 +632,7 @@ class ServerTest extends TestCase
public function testAddGrantTypeWithKey()
{
$server = new Server();
$server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')), 'ac');
$server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->createMock('OAuth2\Storage\AuthorizationCodeInterface')), 'ac');
$grantTypes = $server->getGrantTypes();
$this->assertEquals('ac', key($grantTypes));
@@ -677,7 +641,7 @@ class ServerTest extends TestCase
public function testAddGrantTypeWithKeyNotString()
{
$server = new Server();
$server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')), 42);
$server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->createMock('OAuth2\Storage\AuthorizationCodeInterface')), 42);
$grantTypes = $server->getGrantTypes();
$this->assertEquals('authorization_code', key($grantTypes));
@@ -2,8 +2,12 @@
namespace OAuth2\Storage;
use Yoast\PHPUnitPolyfills\Polyfills\ExpectPHPException;
class PdoTest extends BaseTest
{
use ExpectPHPException;
public function testCreatePdoStorageUsingPdoClass()
{
$dsn = sprintf('sqlite:%s', Bootstrap::getInstance()->getSqliteDir());
@@ -30,11 +34,9 @@ class PdoTest extends BaseTest
$this->assertNotNull($storage->getClientDetails('oauth_test_client'));
}
/**
* @expectedException InvalidArgumentException dsn
*/
public function testCreatePdoStorageWithoutDSNThrowsException()
{
$this->expectErrorMessage('dsn');
$config = array('username' => 'brent', 'password' => 'brentisaballer');
$storage = new Pdo($config);
}
@@ -35,6 +35,17 @@ class BearerTest extends TestCase
$this->assertEquals($response->getParameter('error_description'), 'The content type for POST requests must be "application/x-www-form-urlencoded"');
}
public function testMissingContentTypeExpectsToBeCorrectContent()
{
$bearer = new Bearer();
$request = TestRequest::createPost(array(
'access_token' => 'ThisIsMyAccessToken'
));
$param = $bearer->getAccessTokenParameter($request, $response = new Response());
$this->assertEquals($param, 'ThisIsMyAccessToken');
}
public function testValidRequestUsingAuthorizationHeader()
{
$bearer = new Bearer();
@@ -1,15 +0,0 @@
<?php
require_once(dirname(__FILE__).'/../src/OAuth2/Autoloader.php');
OAuth2\Autoloader::register();
// register test classes
OAuth2\Autoloader::register(dirname(__FILE__).'/lib');
// register vendors if possible
if (file_exists(__DIR__.'/../vendor/autoload.php')) {
require_once(__DIR__.'/../vendor/autoload.php');
}
// remove the dynamoDB database that was created for this build
OAuth2\Storage\Bootstrap::getInstance()->cleanupTravisDynamoDb();
@@ -68,7 +68,7 @@ class Bootstrap
public function getPostgresDriver()
{
try {
$pdo = new \PDO('pgsql:host=localhost;dbname=oauth2_server_php', 'postgres');
$pdo = new \PDO('pgsql:host=localhost;dbname=oauth2_server_php', 'postgres', 'postgres');
return $pdo;
} catch (\PDOException $e) {
@@ -118,7 +118,7 @@ class Bootstrap
if (!$this->mysql) {
$pdo = null;
try {
$pdo = new \PDO('mysql:host=localhost;', 'root');
$pdo = new \PDO('mysql:host=localhost;', 'root', 'root');
} catch (\PDOException $e) {
$this->mysql = new NullStorage('MySQL', 'Unable to connect to MySQL on root@localhost');
}
@@ -352,11 +352,11 @@ class Bootstrap
private function createPostgresDb()
{
if (!`psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='postgres'"`) {
`createuser -s -r postgres`;
if (!`PGPASSWORD=postgres psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='postgres'" -h localhost -U postgres`) {
`PGPASSWORD=postgres createuser -s -r postgres -h localhost -U postgres`;
}
`createdb -O postgres oauth2_server_php`;
`PGPASSWORD=postgres createdb -O postgres oauth2_server_php -h localhost -U postgres`;
}
private function populatePostgresDb(\PDO $pdo)
@@ -366,8 +366,8 @@ class Bootstrap
private function removePostgresDb()
{
if (trim(`psql -l | grep oauth2_server_php | wc -l`)) {
`dropdb oauth2_server_php`;
if (trim(`PGPASSWORD=postgres psql -l -h localhost -U postgres | grep oauth2_server_php | wc -l`)) {
`PGPASSWORD=postgres dropdb oauth2_server_php -h localhost -U postgres`;
}
}
@@ -945,21 +945,6 @@ class Bootstrap
));
}
public function cleanupTravisDynamoDb($prefix = null)
{
if (is_null($prefix)) {
// skip this when not applicable
if (!$this->getEnvVar('TRAVIS') || self::DYNAMODB_PHP_VERSION != $this->getEnvVar('TRAVIS_PHP_VERSION')) {
return;
}
$prefix = sprintf('build_%s_', $this->getEnvVar('TRAVIS_JOB_NUMBER'));
}
$client = $this->getDynamoDbClient();
$this->deleteDynamoDb($client, $prefix);
}
private function getEnvVar($var, $default = null)
{
return isset($_SERVER[$var]) ? $_SERVER[$var] : (getenv($var) ?: $default);
@@ -4,7 +4,7 @@ Types to use Carbon in Doctrine
## Documentation
[Check how to use in the official Carbon documentation](https://carbon.nesbot.com/symfony/)
[Check how to use in the official Carbon documentation](https://carbon.nesbot.com/guide/getting-started/symfony.html)
This package is an externalization of [src/Carbon/Doctrine](https://github.com/briannesbitt/Carbon/tree/2.71.0/src/Carbon/Doctrine)
from `nestbot/carbon` package.
@@ -32,5 +32,10 @@
"email": "kylekatarnls@gmail.com"
}
],
"minimum-stability": "dev"
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "3.x-dev"
}
}
}
@@ -4,13 +4,14 @@ declare(strict_types=1);
namespace Carbon\Doctrine;
use Carbon\CarbonInterface;
use Doctrine\DBAL\Platforms\AbstractPlatform;
interface CarbonDoctrineType
{
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform);
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string;
public function convertToPHPValue(mixed $value, AbstractPlatform $platform);
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?CarbonInterface;
public function convertToDatabaseValue($value, AbstractPlatform $platform);
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string;
}
@@ -62,7 +62,7 @@ trait CarbonTypeConverter
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string
{
if ($value === null) {
return $value;
@@ -79,11 +79,11 @@ trait CarbonTypeConverter
);
}
private function doConvertToPHPValue(mixed $value)
private function doConvertToPHPValue(mixed $value): ?CarbonInterface
{
$class = $this->getCarbonClassName();
if ($value === null || is_a($value, $class)) {
if ($value === null || (is_object($value) && is_a($value, $class))) {
return $value;
}
+19 -1
View File
@@ -26,6 +26,12 @@ use Composer\Semver\VersionParser;
*/
class InstalledVersions
{
/**
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
* @internal
*/
private static $selfDir = null;
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
@@ -322,6 +328,18 @@ class InstalledVersions
self::$installedIsLocalDir = false;
}
/**
* @return string
*/
private static function getSelfDir()
{
if (self::$selfDir === null) {
self::$selfDir = strtr(__DIR__, '\\', '/');
}
return self::$selfDir;
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
@@ -336,7 +354,7 @@ class InstalledVersions
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = strtr(__DIR__, '\\', '/');
$selfDir = self::getSelfDir();
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
+35 -2
View File
@@ -6,12 +6,45 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'AllowDynamicProperties' => $vendorDir . '/symfony/polyfill-php82/Resources/stubs/AllowDynamicProperties.php',
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'CURLStringFile' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'DateError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
'DateException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
'DateInvalidOperationException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',
'DateInvalidTimeZoneException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',
'DateMalformedIntervalStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',
'DateMalformedPeriodStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',
'DateMalformedStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
'DateObjectError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
'DateRangeError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
'DelayedTargetValidation' => $vendorDir . '/symfony/polyfill-php85/Resources/stubs/DelayedTargetValidation.php',
'Deprecated' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/Deprecated.php',
'Filter\\FilterException' => $vendorDir . '/symfony/polyfill-php85/Resources/stubs/Filter/FilterException.php',
'Filter\\FilterFailedException' => $vendorDir . '/symfony/polyfill-php85/Resources/stubs/Filter/FilterFailedException.php',
'NoDiscard' => $vendorDir . '/symfony/polyfill-php85/Resources/stubs/NoDiscard.php',
'Override' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/Override.php',
'Pdo\\Dblib' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/Pdo/Dblib.php',
'Pdo\\Firebird' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/Pdo/Firebird.php',
'Pdo\\Mysql' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/Pdo/Mysql.php',
'Pdo\\Odbc' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/Pdo/Odbc.php',
'Pdo\\Pgsql' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/Pdo/Pgsql.php',
'Pdo\\Sqlite' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/Pdo/Sqlite.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'ReturnTypeWillChange' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
'Random\\BrokenRandomEngineError' => $vendorDir . '/symfony/polyfill-php82/Resources/stubs/Random/BrokenRandomEngineError.php',
'Random\\CryptoSafeEngine' => $vendorDir . '/symfony/polyfill-php82/Resources/stubs/Random/CryptoSafeEngine.php',
'Random\\Engine' => $vendorDir . '/symfony/polyfill-php82/Resources/stubs/Random/Engine.php',
'Random\\Engine\\Secure' => $vendorDir . '/symfony/polyfill-php82/Resources/stubs/Random/Engine/Secure.php',
'Random\\RandomError' => $vendorDir . '/symfony/polyfill-php82/Resources/stubs/Random/RandomError.php',
'Random\\RandomException' => $vendorDir . '/symfony/polyfill-php82/Resources/stubs/Random/RandomException.php',
'ReflectionConstant' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/ReflectionConstant.php',
'RoundingMode' => $vendorDir . '/symfony/polyfill-php84/Resources/stubs/RoundingMode.php',
'SQLite3Exception' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
'SensitiveParameter' => $vendorDir . '/symfony/polyfill-php82/Resources/stubs/SensitiveParameter.php',
'SensitiveParameterValue' => $vendorDir . '/symfony/polyfill-php82/Resources/stubs/SensitiveParameterValue.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Time\\Duration' => $vendorDir . '/symfony/polyfill-time/Resources/stubs/Time/Duration.php',
'Time\\TimeException' => $vendorDir . '/symfony/polyfill-time/Resources/stubs/Time/TimeException.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
+7 -5
View File
@@ -6,16 +6,18 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'5897ea0ac4cccf14d323035e65887801' => $vendorDir . '/symfony/polyfill-php82/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',
'2203a247e6fda86070a5e4e07aed533a' => $vendorDir . '/symfony/clock/Resources/now.php',
'9d2b9fc6db0f153a0a149fefb182415e' => $vendorDir . '/symfony/polyfill-php84/bootstrap.php',
'606a39d89246991a373564698c2d8383' => $vendorDir . '/symfony/polyfill-php85/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
'23f09fe3194f8c2f70923f90d6702129' => $vendorDir . '/illuminate/collections/functions.php',
'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
'04c6c5c2f7095ccf6c481d3e53e1776f' => $vendorDir . '/mustangostang/spyc/Spyc.php',
'89efb1254ef2d1c5d80096acd12c4098' => $vendorDir . '/twig/twig/src/Resources/core.php',
'ffecb95d45175fd40f75be8a23b34f90' => $vendorDir . '/twig/twig/src/Resources/debug.php',
+6 -1
View File
@@ -7,12 +7,17 @@ $baseDir = dirname($vendorDir);
return array(
'Twig\\' => array($vendorDir . '/twig/twig/src'),
'Symfony\\Polyfill\\Php81\\' => array($vendorDir . '/symfony/polyfill-php81'),
'Symfony\\Polyfill\\Time\\' => array($vendorDir . '/symfony/polyfill-time'),
'Symfony\\Polyfill\\Php85\\' => array($vendorDir . '/symfony/polyfill-php85'),
'Symfony\\Polyfill\\Php84\\' => array($vendorDir . '/symfony/polyfill-php84'),
'Symfony\\Polyfill\\Php83\\' => array($vendorDir . '/symfony/polyfill-php83'),
'Symfony\\Polyfill\\Php82\\' => array($vendorDir . '/symfony/polyfill-php82'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'),
'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
'Symfony\\Component\\Clock\\' => array($vendorDir . '/symfony/clock'),
'Stevenmaguire\\OAuth2\\Client\\' => array($vendorDir . '/stevenmaguire/oauth2-keycloak/src'),
'RobThree\\Auth\\' => array($vendorDir . '/robthree/twofactorauth/lib'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
+118 -58
View File
@@ -7,16 +7,18 @@ namespace Composer\Autoload;
class ComposerStaticInit873464e4bd965a3168f133248b1b218b
{
public static $files = array (
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'5897ea0ac4cccf14d323035e65887801' => __DIR__ . '/..' . '/symfony/polyfill-php82/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php',
'2203a247e6fda86070a5e4e07aed533a' => __DIR__ . '/..' . '/symfony/clock/Resources/now.php',
'9d2b9fc6db0f153a0a149fefb182415e' => __DIR__ . '/..' . '/symfony/polyfill-php84/bootstrap.php',
'606a39d89246991a373564698c2d8383' => __DIR__ . '/..' . '/symfony/polyfill-php85/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
'23f09fe3194f8c2f70923f90d6702129' => __DIR__ . '/..' . '/illuminate/collections/functions.php',
'60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php',
'04c6c5c2f7095ccf6c481d3e53e1776f' => __DIR__ . '/..' . '/mustangostang/spyc/Spyc.php',
'89efb1254ef2d1c5d80096acd12c4098' => __DIR__ . '/..' . '/twig/twig/src/Resources/core.php',
'ffecb95d45175fd40f75be8a23b34f90' => __DIR__ . '/..' . '/twig/twig/src/Resources/debug.php',
@@ -25,25 +27,30 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
);
public static $prefixLengthsPsr4 = array (
'T' =>
'T' =>
array (
'Twig\\' => 5,
),
'S' =>
'S' =>
array (
'Symfony\\Polyfill\\Php81\\' => 23,
'Symfony\\Polyfill\\Time\\' => 22,
'Symfony\\Polyfill\\Php85\\' => 23,
'Symfony\\Polyfill\\Php84\\' => 23,
'Symfony\\Polyfill\\Php83\\' => 23,
'Symfony\\Polyfill\\Php82\\' => 23,
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Contracts\\Translation\\' => 30,
'Symfony\\Component\\Translation\\' => 30,
'Symfony\\Component\\Clock\\' => 24,
'Stevenmaguire\\OAuth2\\Client\\' => 28,
),
'R' =>
'R' =>
array (
'RobThree\\Auth\\' => 14,
),
'P' =>
'P' =>
array (
'Psr\\SimpleCache\\' => 16,
'Psr\\Log\\' => 8,
@@ -54,198 +61,218 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
'PhpMimeMailParser\\' => 18,
'PHPMailer\\PHPMailer\\' => 20,
),
'M' =>
'M' =>
array (
'MatthiasMullie\\PathConverter\\' => 29,
'MatthiasMullie\\Minify\\' => 22,
'Mailcow\\' => 8,
),
'L' =>
'L' =>
array (
'League\\OAuth2\\Client\\' => 21,
'LdapRecord\\' => 11,
),
'I' =>
'I' =>
array (
'Illuminate\\Support\\' => 19,
'Illuminate\\Contracts\\' => 21,
),
'H' =>
'H' =>
array (
'Html2Text\\' => 10,
),
'G' =>
'G' =>
array (
'GuzzleHttp\\Psr7\\' => 16,
'GuzzleHttp\\Promise\\' => 19,
'GuzzleHttp\\' => 11,
),
'F' =>
'F' =>
array (
'Firebase\\JWT\\' => 13,
),
'D' =>
'D' =>
array (
'Ddeboer\\Imap\\' => 13,
'DASPRiD\\Enum\\' => 13,
),
'C' =>
'C' =>
array (
'Carbon\\Doctrine\\' => 16,
'Carbon\\' => 7,
),
'B' =>
'B' =>
array (
'BaconQrCode\\' => 12,
),
);
public static $prefixDirsPsr4 = array (
'Twig\\' =>
'Twig\\' =>
array (
0 => __DIR__ . '/..' . '/twig/twig/src',
),
'Symfony\\Polyfill\\Php81\\' =>
'Symfony\\Polyfill\\Time\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php81',
0 => __DIR__ . '/..' . '/symfony/polyfill-time',
),
'Symfony\\Polyfill\\Php80\\' =>
'Symfony\\Polyfill\\Php85\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php85',
),
'Symfony\\Polyfill\\Php84\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php84',
),
'Symfony\\Polyfill\\Php83\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php83',
),
'Symfony\\Polyfill\\Php82\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php82',
),
'Symfony\\Polyfill\\Php80\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Polyfill\\Mbstring\\' =>
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Ctype\\' =>
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'Symfony\\Contracts\\Translation\\' =>
'Symfony\\Contracts\\Translation\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/translation-contracts',
),
'Symfony\\Component\\Translation\\' =>
'Symfony\\Component\\Translation\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/translation',
),
'Stevenmaguire\\OAuth2\\Client\\' =>
'Symfony\\Component\\Clock\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/clock',
),
'Stevenmaguire\\OAuth2\\Client\\' =>
array (
0 => __DIR__ . '/..' . '/stevenmaguire/oauth2-keycloak/src',
),
'RobThree\\Auth\\' =>
'RobThree\\Auth\\' =>
array (
0 => __DIR__ . '/..' . '/robthree/twofactorauth/lib',
),
'Psr\\SimpleCache\\' =>
'Psr\\SimpleCache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/simple-cache/src',
),
'Psr\\Log\\' =>
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log/src',
),
'Psr\\Http\\Message\\' =>
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-factory/src',
1 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Psr\\Http\\Client\\' =>
'Psr\\Http\\Client\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-client/src',
),
'Psr\\Container\\' =>
'Psr\\Container\\' =>
array (
0 => __DIR__ . '/..' . '/psr/container/src',
),
'Psr\\Clock\\' =>
'Psr\\Clock\\' =>
array (
0 => __DIR__ . '/..' . '/psr/clock/src',
),
'PhpMimeMailParser\\' =>
'PhpMimeMailParser\\' =>
array (
0 => __DIR__ . '/..' . '/php-mime-mail-parser/php-mime-mail-parser/src',
),
'PHPMailer\\PHPMailer\\' =>
'PHPMailer\\PHPMailer\\' =>
array (
0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',
),
'MatthiasMullie\\PathConverter\\' =>
'MatthiasMullie\\PathConverter\\' =>
array (
0 => __DIR__ . '/..' . '/matthiasmullie/path-converter/src',
),
'MatthiasMullie\\Minify\\' =>
'MatthiasMullie\\Minify\\' =>
array (
0 => __DIR__ . '/..' . '/matthiasmullie/minify/src',
),
'Mailcow\\' =>
'Mailcow\\' =>
array (
0 => __DIR__ . '/../..' . '/mailcow',
),
'League\\OAuth2\\Client\\' =>
'League\\OAuth2\\Client\\' =>
array (
0 => __DIR__ . '/..' . '/league/oauth2-client/src',
),
'LdapRecord\\' =>
'LdapRecord\\' =>
array (
0 => __DIR__ . '/..' . '/directorytree/ldaprecord/src',
),
'Illuminate\\Support\\' =>
'Illuminate\\Support\\' =>
array (
0 => __DIR__ . '/..' . '/illuminate/collections',
1 => __DIR__ . '/..' . '/illuminate/macroable',
2 => __DIR__ . '/..' . '/illuminate/conditionable',
),
'Illuminate\\Contracts\\' =>
'Illuminate\\Contracts\\' =>
array (
0 => __DIR__ . '/..' . '/illuminate/contracts',
),
'Html2Text\\' =>
'Html2Text\\' =>
array (
0 => __DIR__ . '/..' . '/soundasleep/html2text/src',
),
'GuzzleHttp\\Psr7\\' =>
'GuzzleHttp\\Psr7\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
),
'GuzzleHttp\\Promise\\' =>
'GuzzleHttp\\Promise\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
),
'GuzzleHttp\\' =>
'GuzzleHttp\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
),
'Firebase\\JWT\\' =>
'Firebase\\JWT\\' =>
array (
0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
),
'Ddeboer\\Imap\\' =>
'Ddeboer\\Imap\\' =>
array (
0 => __DIR__ . '/..' . '/ddeboer/imap/src',
),
'DASPRiD\\Enum\\' =>
'DASPRiD\\Enum\\' =>
array (
0 => __DIR__ . '/..' . '/dasprid/enum/src',
),
'Carbon\\Doctrine\\' =>
'Carbon\\Doctrine\\' =>
array (
0 => __DIR__ . '/..' . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine',
),
'Carbon\\' =>
'Carbon\\' =>
array (
0 => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon',
),
'BaconQrCode\\' =>
'BaconQrCode\\' =>
array (
0 => __DIR__ . '/..' . '/bacon/bacon-qr-code/src',
),
);
public static $prefixesPsr0 = array (
'O' =>
'O' =>
array (
'OAuth2' =>
'OAuth2' =>
array (
0 => __DIR__ . '/..' . '/bshaffer/oauth2-server-php/src',
),
@@ -253,12 +280,45 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
);
public static $classMap = array (
'AllowDynamicProperties' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/AllowDynamicProperties.php',
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'CURLStringFile' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'DateError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
'DateException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
'DateInvalidOperationException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',
'DateInvalidTimeZoneException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',
'DateMalformedIntervalStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',
'DateMalformedPeriodStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',
'DateMalformedStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
'DateObjectError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
'DateRangeError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
'DelayedTargetValidation' => __DIR__ . '/..' . '/symfony/polyfill-php85/Resources/stubs/DelayedTargetValidation.php',
'Deprecated' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/Deprecated.php',
'Filter\\FilterException' => __DIR__ . '/..' . '/symfony/polyfill-php85/Resources/stubs/Filter/FilterException.php',
'Filter\\FilterFailedException' => __DIR__ . '/..' . '/symfony/polyfill-php85/Resources/stubs/Filter/FilterFailedException.php',
'NoDiscard' => __DIR__ . '/..' . '/symfony/polyfill-php85/Resources/stubs/NoDiscard.php',
'Override' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/Override.php',
'Pdo\\Dblib' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/Pdo/Dblib.php',
'Pdo\\Firebird' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/Pdo/Firebird.php',
'Pdo\\Mysql' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/Pdo/Mysql.php',
'Pdo\\Odbc' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/Pdo/Odbc.php',
'Pdo\\Pgsql' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/Pdo/Pgsql.php',
'Pdo\\Sqlite' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/Pdo/Sqlite.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'ReturnTypeWillChange' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
'Random\\BrokenRandomEngineError' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/Random/BrokenRandomEngineError.php',
'Random\\CryptoSafeEngine' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/Random/CryptoSafeEngine.php',
'Random\\Engine' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/Random/Engine.php',
'Random\\Engine\\Secure' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/Random/Engine/Secure.php',
'Random\\RandomError' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/Random/RandomError.php',
'Random\\RandomException' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/Random/RandomException.php',
'ReflectionConstant' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/ReflectionConstant.php',
'RoundingMode' => __DIR__ . '/..' . '/symfony/polyfill-php84/Resources/stubs/RoundingMode.php',
'SQLite3Exception' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
'SensitiveParameter' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/SensitiveParameter.php',
'SensitiveParameterValue' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/SensitiveParameterValue.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Time\\Duration' => __DIR__ . '/..' . '/symfony/polyfill-time/Resources/stubs/Time/Duration.php',
'Time\\TimeException' => __DIR__ . '/..' . '/symfony/polyfill-time/Resources/stubs/Time/TimeException.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
File diff suppressed because it is too large. Load diff
+145 -118
View File
@@ -29,18 +29,18 @@
'dev_requirement' => false,
),
'bshaffer/oauth2-server-php' => array(
'pretty_version' => 'v1.11.1',
'version' => '1.11.1.0',
'reference' => '5a0c8000d4763b276919e2106f54eddda6bc50fa',
'pretty_version' => 'v1.14.2',
'version' => '1.14.2.0',
'reference' => '1c715c2d2f71254d1c683b8c89a0f16b61ccd0d6',
'type' => 'library',
'install_path' => __DIR__ . '/../bshaffer/oauth2-server-php',
'aliases' => array(),
'dev_requirement' => false,
),
'carbonphp/carbon-doctrine-types' => array(
'pretty_version' => '3.2.0',
'version' => '3.2.0.0',
'reference' => '18ba5ddfec8976260ead6e866180bd5d2f71aa1d',
'pretty_version' => '3.2.1',
'version' => '3.2.1.0',
'reference' => '5fa5eacafd9ef47c8c6ab9143fc901ba0194d3dc',
'type' => 'library',
'install_path' => __DIR__ . '/../carbonphp/carbon-doctrine-types',
'aliases' => array(),
@@ -56,18 +56,18 @@
'dev_requirement' => false,
),
'ddeboer/imap' => array(
'pretty_version' => '1.13.1',
'version' => '1.13.1.0',
'reference' => '8b772d04b1deadb5df13782fb78c4b648f77496e',
'pretty_version' => '1.19.0',
'version' => '1.19.0.0',
'reference' => '30800b1cfeacc4add5bb418e40a8b6e95a8a04ac',
'type' => 'library',
'install_path' => __DIR__ . '/../ddeboer/imap',
'aliases' => array(),
'dev_requirement' => false,
),
'directorytree/ldaprecord' => array(
'pretty_version' => 'v3.8.5',
'version' => '3.8.5.0',
'reference' => '00e5f088f8c4028d5f398783cccc2e8119a27a65',
'pretty_version' => 'v3.8.6',
'version' => '3.8.6.0',
'reference' => 'a1cab9f078eb4756fc6fad58caea1e3d11cad0ec',
'type' => 'library',
'install_path' => __DIR__ . '/../directorytree/ldaprecord',
'aliases' => array(),
@@ -80,90 +80,90 @@
),
),
'firebase/php-jwt' => array(
'pretty_version' => 'v6.5.0',
'version' => '6.5.0.0',
'reference' => 'e94e7353302b0c11ec3cfff7180cd0b1743975d2',
'pretty_version' => 'v7.2.1',
'version' => '7.2.1.0',
'reference' => '0501f5729b9e2448516674aff07c7d1727869b8e',
'type' => 'library',
'install_path' => __DIR__ . '/../firebase/php-jwt',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/guzzle' => array(
'pretty_version' => '7.5.0',
'version' => '7.5.0.0',
'reference' => 'b50a2a1251152e43f6a37f0fa053e730a67d25ba',
'pretty_version' => '8.3.1',
'version' => '8.3.1.0',
'reference' => '7d9b1f430bb65ac664e120af227bf9a795ad6333',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/promises' => array(
'pretty_version' => '1.5.2',
'version' => '1.5.2.0',
'reference' => 'b94b2807d85443f9719887892882d0329d1e2598',
'pretty_version' => '3.1.0',
'version' => '3.1.0.0',
'reference' => '094d0ec418eb3b1411ea271a180ec95cae6ae933',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '2.4.5',
'version' => '2.4.5.0',
'reference' => '0454e12ef0cd597ccd2adb036f7bda4e7fface66',
'pretty_version' => '3.2.0',
'version' => '3.2.0.0',
'reference' => 'cdc139396207a5eba10c242d241fb014cb098390',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/collections' => array(
'pretty_version' => 'v10.49.0',
'version' => '10.49.0.0',
'reference' => '6ae9c74fa92d4e1824d1b346cd435e8eacdc3232',
'pretty_version' => 'v12.70.2',
'version' => '12.70.2.0',
'reference' => '83313b009c4afb6f02dbc090bdb67809756eefa2',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/collections',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/conditionable' => array(
'pretty_version' => 'v10.49.0',
'version' => '10.49.0.0',
'reference' => '47c700320b7a419f0d188d111f3bbed978fcbd3f',
'pretty_version' => 'v12.70.2',
'version' => '12.70.2.0',
'reference' => 'ec677967c1f2faf90b8428919124d2184a4c9b49',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/conditionable',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/contracts' => array(
'pretty_version' => 'v10.44.0',
'version' => '10.44.0.0',
'reference' => '8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac',
'pretty_version' => 'v12.70.2',
'version' => '12.70.2.0',
'reference' => 'c16fd7ba7d8e6b8f336639ceb6b7e1ff6ed0efb5',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'illuminate/macroable' => array(
'pretty_version' => 'v10.49.0',
'version' => '10.49.0.0',
'reference' => 'dff667a46ac37b634dcf68909d9d41e94dc97c27',
'pretty_version' => 'v12.70.2',
'version' => '12.70.2.0',
'reference' => 'e295d62d89dcdb87e2b1bd70dd14d074a0ed73cc',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/macroable',
'aliases' => array(),
'dev_requirement' => false,
),
'league/oauth2-client' => array(
'pretty_version' => '2.7.0',
'version' => '2.7.0.0',
'reference' => '160d6274b03562ebeb55ed18399281d8118b76c8',
'pretty_version' => '2.9.1',
'version' => '2.9.1.0',
'reference' => '8cedfef9d01a8d1fd2ecfabb41734b17592c4b71',
'type' => 'library',
'install_path' => __DIR__ . '/../league/oauth2-client',
'aliases' => array(),
'dev_requirement' => false,
),
'matthiasmullie/minify' => array(
'pretty_version' => '1.3.66',
'version' => '1.3.66.0',
'reference' => '45fd3b0f1dfa2c965857c6d4a470bea52adc31a6',
'pretty_version' => '1.3.75',
'version' => '1.3.75.0',
'reference' => '76ba4a5f555fd7bf4aa408af608e991569076671',
'type' => 'library',
'install_path' => __DIR__ . '/../matthiasmullie/minify',
'aliases' => array(),
@@ -194,36 +194,27 @@
'dev_requirement' => false,
),
'nesbot/carbon' => array(
'pretty_version' => '2.72.3',
'version' => '2.72.3.0',
'reference' => '0c6fd108360c562f6e4fd1dedb8233b423e91c83',
'pretty_version' => '3.15.1',
'version' => '3.15.1.0',
'reference' => 'ce0e5636fae7d1e99856eb70cae4c719a284aa08',
'type' => 'library',
'install_path' => __DIR__ . '/../nesbot/carbon',
'aliases' => array(),
'dev_requirement' => false,
),
'paragonie/random_compat' => array(
'pretty_version' => 'v9.99.100',
'version' => '9.99.100.0',
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
'type' => 'library',
'install_path' => __DIR__ . '/../paragonie/random_compat',
'aliases' => array(),
'dev_requirement' => false,
),
'php-mime-mail-parser/php-mime-mail-parser' => array(
'pretty_version' => '7.0.0',
'version' => '7.0.0.0',
'reference' => '9d09a017f3f103fec8456211a4a538b80e0eca0d',
'pretty_version' => '7.1.2',
'version' => '7.1.2.0',
'reference' => '81d84bbc6a73b913110e155e98059526825c7ee3',
'type' => 'library',
'install_path' => __DIR__ . '/../php-mime-mail-parser/php-mime-mail-parser',
'aliases' => array(),
'dev_requirement' => false,
),
'phpmailer/phpmailer' => array(
'pretty_version' => 'v6.6.0',
'version' => '6.6.0.0',
'reference' => 'e43bac82edc26ca04b36143a48bde1c051cfd5b1',
'pretty_version' => 'v6.12.0',
'version' => '6.12.0.0',
'reference' => 'd1ac35d784bf9f5e61b424901d5a014967f15b12',
'type' => 'library',
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
'aliases' => array(),
@@ -254,9 +245,9 @@
'dev_requirement' => false,
),
'psr/http-client' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621',
'pretty_version' => '1.0.3',
'version' => '1.0.3.0',
'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-client',
'aliases' => array(),
@@ -269,9 +260,9 @@
),
),
'psr/http-factory' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be',
'pretty_version' => '1.1.0',
'version' => '1.1.0.0',
'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-factory',
'aliases' => array(),
@@ -280,13 +271,13 @@
'psr/http-factory-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0',
0 => '1.1',
),
),
'psr/http-message' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'pretty_version' => '2.0',
'version' => '2.0.0.0',
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
@@ -295,40 +286,31 @@
'psr/http-message-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0',
0 => '2.0',
),
),
'psr/log' => array(
'pretty_version' => '3.0.0',
'version' => '3.0.0.0',
'reference' => 'fe5ea303b0887d5caefd3d431c3e61ad47037001',
'pretty_version' => '3.0.2',
'version' => '3.0.2.0',
'reference' => 'f16e1d5863e37f8d8c2a01719f5b34baa2b714d3',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/log',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/simple-cache' => array(
'pretty_version' => '2.0.0',
'version' => '2.0.0.0',
'reference' => '8707bf3cea6f710bf6ef05491234e3ab06f6432a',
'pretty_version' => '3.0.0',
'version' => '3.0.0.0',
'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/simple-cache',
'aliases' => array(),
'dev_requirement' => false,
),
'ralouphie/getallheaders' => array(
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'type' => 'library',
'install_path' => __DIR__ . '/../ralouphie/getallheaders',
'aliases' => array(),
'dev_requirement' => false,
),
'robthree/twofactorauth' => array(
'pretty_version' => '1.8.1',
'version' => '1.8.1.0',
'reference' => '5afcb45282f1c75562a48d479ecd1732c9bdb11b',
'pretty_version' => '1.8.2',
'version' => '1.8.2.0',
'reference' => '65681de5a324eae05140ac58b08648a60212afc0',
'type' => 'library',
'install_path' => __DIR__ . '/../robthree/twofactorauth',
'aliases' => array(),
@@ -344,72 +326,117 @@
'dev_requirement' => false,
),
'stevenmaguire/oauth2-keycloak' => array(
'pretty_version' => '4.0.0',
'version' => '4.0.0.0',
'reference' => '05ead6bb6bcd2b6f96dfae87c769dcd3e5f6129d',
'pretty_version' => '6.1.1',
'version' => '6.1.1.0',
'reference' => '31bb3b1fa15b444212ed43facc898fafc7c2707a',
'type' => 'library',
'install_path' => __DIR__ . '/../stevenmaguire/oauth2-keycloak',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/clock' => array(
'pretty_version' => 'v7.4.21',
'version' => '7.4.21.0',
'reference' => '07437f612dca89c1894c1db04491002b1e798f03',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/clock',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/deprecation-contracts' => array(
'pretty_version' => 'v3.5.0',
'version' => '3.5.0.0',
'reference' => '0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1',
'pretty_version' => 'v3.7.1',
'version' => '3.7.1.0',
'reference' => 'f3202fa1b5097b0af062dc978b32ecf63404e31d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.24.0',
'version' => '1.24.0.0',
'reference' => '30885182c981ab175d4d034db0f6f469898070ab',
'pretty_version' => 'v1.37.0',
'version' => '1.37.0.0',
'reference' => '141046a8f9477948ff284fa65be2095baafb94f2',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => '9773676c8a1bb1f8d4340a62efe641cf76eda7ec',
'pretty_version' => 'v1.43.3',
'version' => '1.43.3.0',
'reference' => '122889ed24dc000165bcbfd77ec412f15cbdfc6a',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'reference' => '87b68208d5c1188808dd7839ee1e6c8ec3b02f1b',
'pretty_version' => 'v1.43.0',
'version' => '1.43.0.0',
'reference' => '9c6a5d6b01ca51d486c813e9a9c0ed55f208bb74',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php81' => array(
'pretty_version' => 'v1.31.0',
'version' => '1.31.0.0',
'reference' => '4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c',
'symfony/polyfill-php82' => array(
'pretty_version' => 'v1.43.0',
'version' => '1.43.0.0',
'reference' => '843bbe8b2a7934307b749751eede0f111f5d1cfc',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php81',
'install_path' => __DIR__ . '/../symfony/polyfill-php82',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php83' => array(
'pretty_version' => 'v1.43.0',
'version' => '1.43.0.0',
'reference' => '80ccff923a8d61f73ebe9da0aa94e25232f004ce',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php83',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php84' => array(
'pretty_version' => 'v1.43.0',
'version' => '1.43.0.0',
'reference' => '22c6548499cbe5c5bb072fc0c42312dff062a015',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php84',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php85' => array(
'pretty_version' => 'v1.43.0',
'version' => '1.43.0.0',
'reference' => '86a42cbcc07adc331481a5ab310a4024bfc227f6',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php85',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-time' => array(
'pretty_version' => 'v1.42.0',
'version' => '1.42.0.0',
'reference' => 'ac9f1ed802dd58f37e720388130c088434aa09fc',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-time',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/translation' => array(
'pretty_version' => 'v6.4.3',
'version' => '6.4.3.0',
'reference' => '637c51191b6b184184bbf98937702bcf554f7d04',
'pretty_version' => 'v7.4.17',
'version' => '7.4.17.0',
'reference' => '2ee1e4a3b32a528a642babe041ff7c440b213b4b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/translation-contracts' => array(
'pretty_version' => 'v3.4.1',
'version' => '3.4.1.0',
'reference' => '06450585bf65e978026bda220cdebca3f867fde7',
'pretty_version' => 'v3.7.1',
'version' => '3.7.1.0',
'reference' => 'ccb206b98faccc511ebae8e5fad50f2dc0b30621',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation-contracts',
'aliases' => array(),
@@ -422,9 +449,9 @@
),
),
'twig/twig' => array(
'pretty_version' => 'v3.14.0',
'version' => '3.14.0.0',
'reference' => '126b2c97818dbff0cdf3fbfc881aedb3d40aae72',
'pretty_version' => 'v3.30.0',
'version' => '3.30.0.0',
'reference' => '8c737079b726af72ff8ef3c595be9f6a810ea1ef',
'type' => 'library',
'install_path' => __DIR__ . '/../twig/twig',
'aliases' => array(),
+4 -5
View File
@@ -4,8 +4,8 @@
$issues = array();
if (!(PHP_VERSION_ID >= 80100)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
if (!(PHP_VERSION_ID >= 80200)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.2.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
@@ -19,8 +19,7 @@ if ($issues) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
throw new \RuntimeException(
'Composer detected issues in your platform: ' . implode(' ', $issues)
);
}
+3 -3
View File
@@ -17,7 +17,7 @@ return (new PhpCsFixer\Config())
'binary_operator_spaces' => ['default' => 'align_single_space'],
'blank_line_before_statement' => true,
'class_definition' => ['single_item_single_line' => true],
'compact_nullable_typehint' => true,
'compact_nullable_type_declaration' => true,
'concat_space' => ['spacing' => 'one'],
'echo_tag_syntax' => ['format' => 'long'],
'error_suppression' => false,
@@ -39,7 +39,7 @@ return (new PhpCsFixer\Config())
'no_null_property_initialization' => true,
'no_php4_constructor' => true,
'no_superfluous_elseif' => true,
'no_unneeded_curly_braces' => true,
'no_unneeded_braces' => true,
'no_unneeded_final_method' => true,
'no_unreachable_default_argument_value' => true,
'no_useless_else' => true,
@@ -49,7 +49,7 @@ return (new PhpCsFixer\Config())
'php_unit_set_up_tear_down_visibility' => true,
'php_unit_strict' => true,
'php_unit_test_annotation' => true,
'php_unit_test_case_static_method_calls' => true,
'php_unit_test_case_static_method_calls' => false,
'php_unit_test_class_requires_covers' => false,
'phpdoc_add_missing_param_annotation' => true,
'phpdoc_order' => true,
+20 -22
View File
@@ -2,12 +2,12 @@
[![Latest Stable Version](https://img.shields.io/packagist/v/ddeboer/imap.svg)](https://packagist.org/packages/ddeboer/imap)
[![Downloads](https://img.shields.io/packagist/dt/ddeboer/imap.svg)](https://packagist.org/packages/ddeboer/imap)
[![Integrate](https://github.com/ddeboer/imap/workflows/Integrate/badge.svg?branch=master)](https://github.com/ddeboer/imap/actions)
[![Integrate](https://github.com/ddeboer/imap/workflows/CI/badge.svg)](https://github.com/ddeboer/imap/actions)
[![Code Coverage](https://codecov.io/gh/ddeboer/imap/coverage.svg?branch=master)](https://codecov.io/gh/ddeboer/imap?branch=master)
A PHP IMAP library to read and process e-mails over IMAP protocol, built with robust Object-Oriented architecture.
This library requires PHP >= 7.4 with [IMAP](https://www.php.net/manual/en/book.imap.php),
This library requires PHP >= 8.2 with [IMAP](https://www.php.net/manual/en/book.imap.php),
[iconv](https://www.php.net/manual/en/book.iconv.php) and
[Multibyte String](https://www.php.net/manual/en/book.mbstring.php) extensions installed.
@@ -157,7 +157,7 @@ By the way most of the common search criteria are available and functioning, bro
References:
1. https://stackoverflow.com/questions/36356715/imap-search-unknown-search-criterion-or
1. imap-2007f.tar.gz: `./src/c-client/mail.c` and `./docs/internal.txt`
2. imap-2007f.tar.gz: `./src/c-client/mail.c` and `./docs/internal.txt`
#### Message Properties and Operations
@@ -182,19 +182,29 @@ $message->isDraft();
$message->isSeen();
```
Get message headers as a [\Ddeboer\Imap\Message\Headers](/src/Ddeboer/Imap/Message/Headers.php) object:
Get message headers as a [\Ddeboer\Imap\Message\Headers](/src/Message/Headers.php) object:
```php
$message->getHeaders();
```
Get message body as HTML or plain text:
Get message body as HTML or plain text (only first part):
```php
$message->getBodyHtml(); // Content of text/html part, if present
$message->getBodyText(); // Content of text/plain part, if present
```
Get complete body (all parts):
```php
$body = $message->getCompleteBodyHtml(); // Content of text/html part, if present
if ($body === null) { // If body is null, there are no HTML parts, so let's try getting the text body
$body = $message->getCompleteBodyText(); // Content of text/plain part, if present
}
```
Reading the message body keeps the message as unseen.
If you want to mark the message as seen:
@@ -284,24 +294,12 @@ Mockability is granted by interfaces present for each API.
Dig into [MockabilityTest](tests/MockabilityTest.php) for an example of a
mocked workflow.
## Running the Tests
## Contributing: run the build locally
This library is functionally tested on [Travis CI](https://travis-ci.org/ddeboer/imap)
against a local Dovecot server.
Docker is needed to run the build on your computer.
If you have your own IMAP (test) account, you can run the tests locally by
providing your IMAP credentials:
First command you need to run is `make start-imap-server`, which starts an IMAP server locally.
```bash
$ composer install
$ IMAP_SERVER_NAME="my.imap.server.com" IMAP_SERVER_PORT="60993" IMAP_USERNAME="johndoe" IMAP_PASSWORD="p4ssword" vendor/bin/phpunit
```
Then the local build can be triggered with a bare `make`.
You can also copy `phpunit.xml.dist` file to a custom `phpunit.xml` and put
these environment variables in it.
**WARNING** Tests create new mailboxes without removing them.
```
$ docker-compose run tests
```
When you finish the development, stop the local IMAP server with `make stop-imap-server`.
+9 -13
View File
@@ -22,19 +22,20 @@
}
],
"require": {
"php": "^8.0.1",
"php": "~8.2.0 || ~8.3.0",
"ext-dom": "*",
"ext-iconv": "*",
"ext-imap": "*",
"ext-libxml": "*",
"ext-mbstring": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^v3.4.0",
"laminas/laminas-mail": "^2.15.1",
"malukenho/mcbumpface": "^1.1.5",
"phpstan/phpstan": "^1.3.3",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.1.0",
"phpunit/phpunit": "^9.5.11"
"friendsofphp/php-cs-fixer": "^3.38.2",
"laminas/laminas-mail": "^2.25.1",
"phpstan/phpstan": "^1.10.43",
"phpstan/phpstan-phpunit": "^1.3.15",
"phpstan/phpstan-strict-rules": "^1.5.2",
"phpunit/phpunit": "^10.4.2"
},
"autoload": {
"psr-4": {
@@ -45,10 +46,5 @@
"psr-4": {
"Ddeboer\\Imap\\Tests\\": "tests/"
}
},
"config": {
"allow-plugins": {
"malukenho/mcbumpface": true
}
}
}
+4 -2
View File
@@ -50,9 +50,11 @@ final class Connection implements ConnectionInterface
public function close(int $flag = 0): bool
{
$stream = $this->resource->getStream();
$this->resource->clearLastMailboxUsedCache();
return \imap_close($this->resource->getStream(), $flag);
return \imap_close($stream, $flag);
}
public function getQuota(string $root = 'INBOX'): array
@@ -61,7 +63,7 @@ final class Connection implements ConnectionInterface
$errorNumber = 0;
\set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
$errorMessage = $message;
$errorNumber = $nr;
$errorNumber = $nr;
return true;
});
@@ -6,7 +6,6 @@ namespace Ddeboer\Imap;
use Ddeboer\Imap\Exception\CreateMailboxException;
use Ddeboer\Imap\Exception\DeleteMailboxException;
use Ddeboer\Imap\Exception\InvalidResourceException;
use Ddeboer\Imap\Exception\MailboxDoesNotExistException;
/**
@@ -31,8 +30,6 @@ interface ConnectionInterface extends \Countable
/**
* Check if the connection is still active.
*
* @throws InvalidResourceException If connection was closed
*/
public function ping(): bool;
@@ -4,6 +4,6 @@ declare(strict_types=1);
namespace Ddeboer\Imap\Exception;
final class InvalidResourceException extends AbstractException
final class RenameMailboxException extends AbstractException
{
}
+5 -20
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Ddeboer\Imap;
use Ddeboer\Imap\Exception\InvalidResourceException;
use Ddeboer\Imap\Exception\ReopenMailboxException;
use IMAP\Connection;
@@ -13,33 +12,21 @@ use IMAP\Connection;
*/
final class ImapResource implements ImapResourceInterface
{
/**
* @var resource
*/
private $resource;
private ?MailboxInterface $mailbox = null;
private Connection $resource;
private ?MailboxInterface $mailbox;
private static ?string $lastMailboxUsedCache = null;
/**
* Constructor.
*
* @param Connection|resource $resource
*/
public function __construct($resource, MailboxInterface $mailbox = null)
public function __construct(Connection $resource, MailboxInterface $mailbox = null)
{
$this->resource = $resource;
$this->mailbox = $mailbox;
}
public function getStream()
public function getStream(): Connection
{
if (
!$this->resource instanceof Connection
&& (false === \is_resource($this->resource) || 'imap' !== \get_resource_type($this->resource))
) {
throw new InvalidResourceException('Supplied resource is not a valid imap resource');
}
$this->initMailbox();
return $this->resource;
@@ -76,10 +63,8 @@ final class ImapResource implements ImapResourceInterface
/**
* Check whether the current mailbox is open.
*
* @param resource $resource
*/
private static function isMailboxOpen(MailboxInterface $mailbox, $resource): bool
private static function isMailboxOpen(MailboxInterface $mailbox, Connection $resource): bool
{
$currentMailboxName = $mailbox->getFullEncodedName();
if ($currentMailboxName === self::$lastMailboxUsedCache) {
@@ -4,18 +4,14 @@ declare(strict_types=1);
namespace Ddeboer\Imap;
use Ddeboer\Imap\Exception\InvalidResourceException;
use IMAP\Connection;
interface ImapResourceInterface
{
/**
* Get IMAP resource stream.
*
* @throws InvalidResourceException
*
* @return resource
*/
public function getStream();
public function getStream(): Connection;
/**
* Clear last mailbox used cache.
+19 -6
View File
@@ -4,12 +4,12 @@ declare(strict_types=1);
namespace Ddeboer\Imap;
use DateTimeInterface;
use Ddeboer\Imap\Exception\ImapNumMsgException;
use Ddeboer\Imap\Exception\ImapStatusException;
use Ddeboer\Imap\Exception\InvalidSearchCriteriaException;
use Ddeboer\Imap\Exception\MessageCopyException;
use Ddeboer\Imap\Exception\MessageMoveException;
use Ddeboer\Imap\Exception\RenameMailboxException;
use Ddeboer\Imap\Search\ConditionInterface;
use Ddeboer\Imap\Search\LogicalOperator\All;
@@ -41,6 +41,23 @@ final class Mailbox implements MailboxInterface
return $this->name;
}
public function renameTo(string $name): bool
{
$encodedName = \mb_convert_encoding($name, 'UTF7-IMAP', 'UTF-8');
$oldFullName = $this->getFullEncodedName();
$newFullName = \preg_replace('/' . \preg_quote(\mb_convert_encoding($this->name, 'UTF7-IMAP', 'UTF-8')) . '$/', $encodedName, $oldFullName);
\assert(null !== $newFullName);
$return = \imap_renamemailbox($this->resource->getStream(), $oldFullName, $newFullName);
if (false === $return) {
throw new RenameMailboxException('Could not rename mailbox');
}
$this->name = $name;
$this->info->name = $newFullName;
return true;
}
public function getEncodedName(): string
{
/** @var string $name */
@@ -104,10 +121,6 @@ final class Mailbox implements MailboxInterface
}
$query = $search->toString();
if (\PHP_VERSION_ID < 80000) {
$descending = (int) $descending;
}
// We need to clear the stack to know whether imap_last_error()
// is related to this imap_search
\imap_errors();
@@ -178,7 +191,7 @@ final class Mailbox implements MailboxInterface
return $this->getMessages();
}
public function addMessage(string $message, string $options = null, DateTimeInterface $internalDate = null): bool
public function addMessage(string $message, string $options = null, \DateTimeInterface $internalDate = null): bool
{
$arguments = [
$this->resource->getStream(),
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Ddeboer\Imap;
use DateTimeInterface;
use Ddeboer\Imap\Message\PartInterface;
use Ddeboer\Imap\Search\ConditionInterface;
@@ -20,6 +19,11 @@ interface MailboxInterface extends \Countable, \IteratorAggregate
*/
public function getName(): string;
/**
* Set new mailbox name.
*/
public function renameTo(string $name): bool;
/**
* Get mailbox encoded path.
*/
@@ -92,7 +96,7 @@ interface MailboxInterface extends \Countable, \IteratorAggregate
/**
* Add a message to the mailbox.
*/
public function addMessage(string $message, string $options = null, DateTimeInterface $internalDate = null): bool;
public function addMessage(string $message, string $options = null, \DateTimeInterface $internalDate = null): bool;
/**
* Returns a tree of threaded message for the current Mailbox.
+10 -5
View File
@@ -49,7 +49,7 @@ final class Message extends Message\AbstractMessage implements MessageInterface
$errorNumber = 0;
\set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
$errorMessage = $message;
$errorNumber = $nr;
$errorNumber = $nr;
return true;
});
@@ -80,7 +80,6 @@ final class Message extends Message\AbstractMessage implements MessageInterface
}
$this->messageNumberVerified = true;
$msgno = null;
\set_error_handler(static function (): bool {
return true;
});
@@ -89,7 +88,7 @@ final class Message extends Message\AbstractMessage implements MessageInterface
\restore_error_handler();
if (\is_numeric($msgno) && $msgno > 0) {
if ($msgno > 0) {
$this->imapMsgNo = $msgno;
return;
@@ -133,6 +132,14 @@ final class Message extends Message\AbstractMessage implements MessageInterface
return $this->rawMessage;
}
/**
* @param resource|string $file the path to the saved file as a string, or a valid file descriptor
*/
public function saveRawMessage($file): void
{
$this->doSaveContent($file, '');
}
public function getHeaders(): Message\Headers
{
if (null === $this->headers) {
@@ -198,8 +205,6 @@ final class Message extends Message\AbstractMessage implements MessageInterface
public function maskAsSeen(): bool
{
\trigger_error(\sprintf('%s is deprecated and will be removed in 2.0. Use %s::markAsSeen instead.', __METHOD__, __CLASS__), \E_USER_DEPRECATED);
return $this->markAsSeen();
}
@@ -203,23 +203,86 @@ abstract class AbstractMessage extends AbstractPart
}
/**
* Get body HTML.
* Get first body HTML part.
*/
final public function getBodyHtml(): ?string
{
$iterator = new \RecursiveIteratorIterator($this, \RecursiveIteratorIterator::SELF_FIRST);
$htmlParts = $this->getAllContentsBySubtype(self::SUBTYPE_HTML);
return $htmlParts[0] ?? null;
}
/**
* Get all contents parts of specific subtype (self::SUBTYPE_HTML or self::SUBTYPE_PLAIN).
*
* @return string[]
*/
final public function getAllContentsBySubtype(string $subtype): array
{
$iterator = new \RecursiveIteratorIterator($this, \RecursiveIteratorIterator::SELF_FIRST);
$parts = [];
/** @var PartInterface $part */
foreach ($iterator as $part) {
if (self::SUBTYPE_HTML === $part->getSubtype()) {
return $part->getDecodedContent();
if ($subtype === $part->getSubtype()) {
$parts[] = $part->getDecodedContent();
}
}
if (\count($parts) > 0) {
return $parts;
}
// If message has no parts and is of right type, return content of message.
if ($subtype === $this->getSubtype()) {
return [$this->getDecodedContent()];
}
return [];
}
/**
* Get body HTML parts.
*
* @return string[]
*/
final public function getBodyHtmlParts(): array
{
return $this->getAllContentsBySubtype(self::SUBTYPE_HTML);
}
/**
* Get all body HTML parts merged into 1 html.
*/
final public function getCompleteBodyHtml(): ?string
{
$htmlParts = $this->getAllContentsBySubtype(self::SUBTYPE_HTML);
if (1 === \count($htmlParts)) {
return $htmlParts[0];
}
if (0 === \count($htmlParts)) {
return null;
}
\libxml_use_internal_errors(true); // Suppress parse errors, get errors with libxml_get_errors();
$newDom = new \DOMDocument();
$newBody = '';
$newDom->loadHTML(\implode('', $htmlParts));
$bodyTags = $newDom->getElementsByTagName('body');
foreach ($bodyTags as $body) {
foreach ($body->childNodes as $node) {
$newBody .= $newDom->saveHTML($node);
}
}
// If message has no parts and is HTML, return content of message itself.
if (self::SUBTYPE_HTML === $this->getSubtype()) {
return $this->getDecodedContent();
}
$newDom = new \DOMDocument();
$newDom->loadHTML($newBody);
return null;
$completeHtml = $newDom->saveHTML();
return false === $completeHtml ? null : $completeHtml;
}
/**
@@ -227,19 +290,28 @@ abstract class AbstractMessage extends AbstractPart
*/
final public function getBodyText(): ?string
{
$iterator = new \RecursiveIteratorIterator($this, \RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $part) {
if (self::SUBTYPE_PLAIN === $part->getSubtype()) {
return $part->getDecodedContent();
}
$plainParts = $this->getAllContentsBySubtype(self::SUBTYPE_PLAIN);
return $plainParts[0] ?? null;
}
/**
* Get all body PLAIN parts merged into 1 string.
*
* @return null|string Null if message has no PLAIN message parts
*/
final public function getCompleteBodyText(): ?string
{
$plainParts = $this->getAllContentsBySubtype(self::SUBTYPE_PLAIN);
if (1 === \count($plainParts)) {
return $plainParts[0];
}
if (0 === \count($plainParts)) {
return null;
}
// If message has no parts, return content of message itself.
if (self::SUBTYPE_PLAIN === $this->getSubtype()) {
return $this->getDecodedContent();
}
return null;
return \implode("\n", $plainParts);
}
/**
@@ -269,7 +341,7 @@ abstract class AbstractMessage extends AbstractPart
$attachments[] = $childPart;
}
if ($childPart->hasChildren()) {
$attachments = \array_merge($attachments, self::gatherAttachments($childPart));
$attachments = [...$attachments, ...self::gatherAttachments($childPart)];
}
}
@@ -56,8 +56,7 @@ abstract class AbstractPart implements PartInterface
private ?string $encoding = null;
private ?string $disposition = null;
private ?string $description = null;
/** @var null|int|string */
private $bytes;
private string|int|null $bytes;
private ?string $lines = null;
private ?string $content = null;
private ?string $decodedContent = null;
@@ -256,6 +255,26 @@ abstract class AbstractPart implements PartInterface
return $return;
}
/**
* Save raw message content to file.
*
* @param resource|string $file the path to the saved file as a string, or a valid file descriptor
*/
final protected function doSaveContent($file, string $partNumber): void
{
$return = \imap_savebody(
$this->resource->getStream(),
$file,
$this->getNumber(),
$partNumber,
\FT_UID | \FT_PEEK
);
if (false === $return) {
throw new ImapFetchbodyException('imap_savebody failed');
}
}
final public function getParts(): array
{
$this->lazyParseStructure();
@@ -265,8 +284,6 @@ abstract class AbstractPart implements PartInterface
/**
* Get current child part.
*
* @return mixed
*/
#[\ReturnTypeWillChange]
final public function current()
@@ -360,7 +377,7 @@ abstract class AbstractPart implements PartInterface
// When the message is not multipart and the body is the attachment content
// Prevents infinite recursion
if (self::isAttachment($this->structure) && !$this instanceof Attachment) {
if (!$this instanceof Attachment && self::isAttachment($this->structure)) {
$this->parts[] = new Attachment($this->resource, $this->getNumber(), '1', $this->structure);
}
@@ -372,12 +389,11 @@ abstract class AbstractPart implements PartInterface
}
foreach ($parts as $key => $partStructure) {
$partNumber = (!$this instanceof Message) ? $this->partNumber . '.' : '';
$partNumber .= (string) ($key + 1);
$partNumber .= $key + 1;
$newPartClass = self::isAttachment($partStructure)
? Attachment::class
: SimplePart::class
;
: SimplePart::class;
$this->parts[] = new $newPartClass($this->resource, $this->getNumber(), $partNumber, $partStructure);
}
@@ -400,9 +416,9 @@ abstract class AbstractPart implements PartInterface
}
if (
'inline' === \strtolower($part->disposition)
'inline' === \strtolower($part->disposition)
&& self::SUBTYPE_PLAIN !== \strtoupper($part->subtype)
&& self::SUBTYPE_HTML !== \strtoupper($part->subtype)
&& self::SUBTYPE_HTML !== \strtoupper($part->subtype)
) {
return true;
}
@@ -427,10 +443,6 @@ abstract class AbstractPart implements PartInterface
}
*/
if (self::SUBTYPE_RFC822 === \strtoupper($part->subtype)) {
return true;
}
return false;
return self::SUBTYPE_RFC822 === \strtoupper($part->subtype);
}
}
@@ -18,6 +18,13 @@ interface BasicMessageInterface extends PartInterface
*/
public function getRawMessage(): string;
/**
* Save the raw message, including all headers, parts, etc. unencoded and unparsed to file.
*
* @param resource|string $file the path to the saved file as a string, or a valid file descriptor
*/
public function saveRawMessage($file): void;
/**
* Get message headers.
*/
@@ -109,17 +116,45 @@ interface BasicMessageInterface extends PartInterface
public function getReferences(): array;
/**
* Get body HTML.
* Get message parts by type.
*
* @return string[]
*/
public function getAllContentsBySubtype(string $subtype): array;
/**
* Get first body HTML part.
*
* @return null|string Null if message has no HTML message part
*/
public function getBodyHtml(): ?string;
/**
* Get all body HTML parts as array.
*
* @return string[]
*/
public function getBodyHtmlParts(): array;
/**
* Get all body HTML parts merged into 1 html.
*
* @return null|string Null if message has no HTML message parts
*/
public function getCompleteBodyHtml(): ?string;
/**
* Get body text.
*/
public function getBodyText(): ?string;
/**
* Get all body PLAIN parts merged into 1 string.
*
* @return null|string Null if message has no PLAIN message parts
*/
public function getCompleteBodyText(): ?string;
/**
* Get attachments (if any) linked to this e-mail.
*
@@ -38,6 +38,14 @@ final class EmbeddedMessage extends AbstractMessage implements EmbeddedMessageIn
return $this->rawMessage;
}
/**
* @param resource|string $file the path to the saved file as a string, or a valid file descriptor
*/
public function saveRawMessage($file): void
{
$this->doSaveContent($file, $this->getPartNumber());
}
/**
* Get content part number.
*/
@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Ddeboer\Imap\Message;
use Ddeboer\Imap\Exception\UnsupportedCharsetException;
final class Headers extends Parameters
{
public function __construct(\stdClass $headers)
@@ -14,7 +16,11 @@ final class Headers extends Parameters
$headers = \array_change_key_case((array) $headers);
foreach ($headers as $key => $value) {
$this[$key] = $this->parseHeader($key, $value);
try {
$this[$key] = $this->parseHeader($key, $value);
} catch (UnsupportedCharsetException) {
// safely skip header with unsupported charset
}
}
}
@@ -50,7 +56,6 @@ final class Headers extends Parameters
case 'sender':
case 'return_path':
\assert(\is_array($value));
/** @var \stdClass $address */
foreach ($value as $address) {
if (isset($address->mailbox)) {
$address->host = $address->host ?? null;
@@ -304,7 +304,7 @@ final class Transcoder
$errorNumber = 0;
\set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
$errorMessage = $message;
$errorNumber = $nr;
$errorNumber = $nr;
return true;
});
@@ -39,8 +39,8 @@ final class MessageIterator extends \ArrayIterator implements MessageIteratorInt
'The current value "%s" isn\'t an integer and doesn\'t represent a message;'
. ' try to cycle this "%s" with a native php function like foreach or with the method getArrayCopy(),'
. ' or check it by calling the methods valid().',
\is_object($current) ? \get_class($current) : \gettype($current),
static::class
\get_debug_type($current),
self::class
));
}
@@ -4,8 +4,6 @@ declare(strict_types=1);
namespace Ddeboer\Imap\Search;
use DateTimeInterface;
/**
* Represents a date condition.
*/
@@ -19,14 +17,14 @@ abstract class AbstractDate implements ConditionInterface
/**
* The date to be used for the condition.
*/
private DateTimeInterface $date;
private \DateTimeInterface $date;
/**
* Constructor.
*
* @param DateTimeInterface $date optional date for the condition
* @param \DateTimeInterface $date optional date for the condition
*/
public function __construct(DateTimeInterface $date, string $dateFormat = 'j-M-Y')
public function __construct(\DateTimeInterface $date, string $dateFormat = 'j-M-Y')
{
$this->date = $date;
$this->dateFormat = $dateFormat;
+1 -1
View File
@@ -67,7 +67,7 @@ final class Server implements ServerInterface
$errorNumber = 0;
\set_error_handler(static function ($nr, $message) use (&$errorMessage, &$errorNumber): bool {
$errorMessage = $message;
$errorNumber = $nr;
$errorNumber = $nr;
return true;
});
@@ -36,8 +36,8 @@
"psr/log": "*",
"nesbot/carbon": "*",
"psr/simple-cache": "^1.0|^2.0|^3.0",
"illuminate/contracts": "^8.0|^9.0|^10.0|^11.0|^12.0",
"illuminate/collections": "^8.0|^9.0|^10.0|^11.0|^12.0"
"illuminate/contracts": "^8.0|^9.0|^10.0|^11.0|^12.0|^13.0",
"illuminate/collections": "^8.0|^9.0|^10.0|^11.0|^12.0|^13.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
@@ -3,7 +3,9 @@
namespace LdapRecord\Auth;
use Exception;
use LdapRecord\Configuration\ConfigurationException;
use LdapRecord\Configuration\DomainConfiguration;
use LdapRecord\ConnectionException;
use LdapRecord\Events\DispatcherInterface;
use LdapRecord\LdapInterface;
@@ -71,7 +73,7 @@ class Guard
* Attempt binding a user to the LDAP server. Supports sasl and anonymous binding.
*
* @throws BindException
* @throws \LdapRecord\ConnectionException
* @throws ConnectionException
*/
public function bind(?string $username = null, ?string $password = null): void
{
@@ -102,7 +104,7 @@ class Guard
/**
* Authenticate by binding to the LDAP server.
*
* @throws \LdapRecord\ConnectionException
* @throws ConnectionException
*/
protected function authenticate(?string $username = null, ?string $password = null): bool
{
@@ -119,8 +121,8 @@ class Guard
* Bind to the LDAP server using the configured username and password.
*
* @throws BindException
* @throws \LdapRecord\ConnectionException
* @throws \LdapRecord\Configuration\ConfigurationException
* @throws ConnectionException
* @throws ConfigurationException
*/
public function bindAsConfiguredUser(): void
{
@@ -89,7 +89,7 @@ class Connection
/**
* Set the connection configuration.
*
* @throws Configuration\ConfigurationException
* @throws ConfigurationException
*/
public function setConfiguration(DomainConfiguration|array $config = []): void
{
Loaded 100 of 1311 files, more files were not shown because too many files have changed in this diff. Show more