mirror of
https://github.com/wallabag/wallabag.git
synced 2025-02-28 08:26:29 +00:00
Merge pull request #7947 from wallabag/migrate-from-guzzle-to-symfony-httpclient
Migrate from Guzzle to Symfony HttpClient
This commit is contained in:
commit
8e0b9d4d94
14 changed files with 661 additions and 1303 deletions
|
@ -32,7 +32,6 @@ class AppKernel extends Kernel
|
|||
new BabDev\PagerfantaBundle\BabDevPagerfantaBundle(),
|
||||
new FOS\JsRoutingBundle\FOSJsRoutingBundle(),
|
||||
new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(),
|
||||
new Http\HttplugBundle\HttplugBundle(),
|
||||
new Sentry\SentryBundle\SentryBundle(),
|
||||
new Twig\Extra\TwigExtraBundle\TwigExtraBundle(),
|
||||
new Symfony\WebpackEncoreBundle\WebpackEncoreBundle(),
|
||||
|
|
|
@ -48,6 +48,10 @@ framework:
|
|||
X-Accept: 'application/json'
|
||||
request_html_function.client:
|
||||
scope: '.*'
|
||||
browser.client:
|
||||
scope: '.*'
|
||||
verify_host: false
|
||||
verify_peer: false
|
||||
|
||||
# Twig Configuration
|
||||
twig:
|
||||
|
@ -452,17 +456,6 @@ sensio_framework_extra:
|
|||
router:
|
||||
annotations: false
|
||||
|
||||
httplug:
|
||||
clients:
|
||||
wallabag:
|
||||
factory: Wallabag\Helper\HttpClientFactory
|
||||
config:
|
||||
defaults:
|
||||
timeout: 10
|
||||
plugins: ['httplug.plugin.logger']
|
||||
discovery:
|
||||
client: false
|
||||
|
||||
# define custom entity so we can override length attribute to fix utf8mb4 issue
|
||||
craue_config:
|
||||
entity_name: Wallabag\Entity\InternalSetting
|
||||
|
|
|
@ -191,11 +191,17 @@ services:
|
|||
tags:
|
||||
- { name: doctrine.event_subscriber }
|
||||
|
||||
psr18.wallabag.client:
|
||||
class: Symfony\Component\HttpClient\Psr18Client
|
||||
arguments:
|
||||
$client: '@Wallabag\HttpClient\WallabagClient'
|
||||
|
||||
Graby\Graby:
|
||||
arguments:
|
||||
$config:
|
||||
error_message: '%wallabag.fetching_error_message%'
|
||||
error_message_title: '%wallabag.fetching_error_message_title%'
|
||||
$client: '@psr18.wallabag.client'
|
||||
calls:
|
||||
- [ setLogger, [ "@logger" ] ]
|
||||
tags:
|
||||
|
@ -205,9 +211,6 @@ services:
|
|||
arguments:
|
||||
$config: {}
|
||||
|
||||
wallabag.http_client:
|
||||
alias: 'httplug.client.wallabag'
|
||||
|
||||
Wallabag\SiteConfig\GrabySiteConfigBuilder:
|
||||
tags:
|
||||
- { name: monolog.logger, channel: graby }
|
||||
|
@ -216,11 +219,9 @@ services:
|
|||
Wallabag\SiteConfig\SiteConfigBuilder:
|
||||
alias: Wallabag\SiteConfig\GrabySiteConfigBuilder
|
||||
|
||||
GuzzleHttp\Cookie\CookieJar: ~
|
||||
|
||||
Wallabag\Helper\HttpClientFactory:
|
||||
calls:
|
||||
- ['addSubscriber', ['@Wallabag\Guzzle\AuthenticatorSubscriber']]
|
||||
Symfony\Component\BrowserKit\HttpBrowser:
|
||||
arguments:
|
||||
$client: '@browser.client'
|
||||
|
||||
RulerZ\RulerZ:
|
||||
alias: rulerz
|
||||
|
|
|
@ -29,8 +29,6 @@ $config
|
|||
'mnapoli/piwik-twig-extension',
|
||||
'ocramius/proxy-manager',
|
||||
'pagerfanta/twig',
|
||||
'php-http/client-common',
|
||||
'php-http/httplug',
|
||||
'php-http/mock-client',
|
||||
'phpstan/extension-installer',
|
||||
'phpstan/phpstan',
|
||||
|
@ -39,13 +37,11 @@ $config
|
|||
'phpstan/phpstan-symfony',
|
||||
'psr/http-client',
|
||||
'psr/http-factory',
|
||||
'psr/http-message',
|
||||
'rulerz-php/doctrine-orm',
|
||||
'scheb/2fa-qr-code',
|
||||
'scheb/2fa-trusted-device',
|
||||
'shipmonk/composer-dependency-analyser',
|
||||
'symfony/asset',
|
||||
'symfony/browser-kit',
|
||||
'symfony/css-selector',
|
||||
'symfony/doctrine-bridge',
|
||||
'symfony/google-mailer',
|
||||
|
@ -57,10 +53,8 @@ $config
|
|||
'twig/string-extra',
|
||||
], [ErrorType::UNUSED_DEPENDENCY])
|
||||
->ignoreErrorsOnPackages([
|
||||
'guzzlehttp/streams',
|
||||
'monolog/monolog',
|
||||
'symfony/filesystem',
|
||||
'symfony/http-client',
|
||||
], [ErrorType::PROD_DEPENDENCY_ONLY_IN_DEV])
|
||||
->ignoreErrorsOnPackages([
|
||||
'dama/doctrine-test-bundle',
|
||||
|
|
|
@ -75,9 +75,7 @@
|
|||
"friendsofsymfony/oauth-server-bundle": "dev-master#dc8ff343363cf794d30eb1a123610d186a43f162",
|
||||
"friendsofsymfony/rest-bundle": "^3.6",
|
||||
"friendsofsymfony/user-bundle": "^3.2.1",
|
||||
"guzzlehttp/guzzle": "^5.3.4",
|
||||
"guzzlehttp/psr7": "^2.6.2",
|
||||
"guzzlehttp/streams": "^3.0",
|
||||
"html2text/html2text": "^4.3.1",
|
||||
"incenteev/composer-parameter-handler": "^2.2",
|
||||
"j0k3r/graby": "^2.4.5",
|
||||
|
@ -99,10 +97,6 @@
|
|||
"pagerfanta/twig": "^3.8",
|
||||
"php-amqplib/php-amqplib": "^3.6.1",
|
||||
"php-amqplib/rabbitmq-bundle": "^2.14.0",
|
||||
"php-http/client-common": "^2.7.1",
|
||||
"php-http/guzzle5-adapter": "^2.0",
|
||||
"php-http/httplug": "^2.4",
|
||||
"php-http/httplug-bundle": "^1.32",
|
||||
"pragmarx/recovery": "^0.2.1",
|
||||
"predis/predis": "^2.2.2",
|
||||
"psr/http-client": "^1.0.3",
|
||||
|
@ -122,6 +116,7 @@
|
|||
"spiriitlabs/form-filter-bundle": "^10.0",
|
||||
"stof/doctrine-extensions-bundle": "^1.11.0",
|
||||
"symfony/asset": "^5.4.35",
|
||||
"symfony/browser-kit": "^5.4.35",
|
||||
"symfony/config": "^5.4.35",
|
||||
"symfony/console": "^5.4.35",
|
||||
"symfony/dependency-injection": "^5.4.35",
|
||||
|
@ -182,7 +177,6 @@
|
|||
"phpstan/phpstan-symfony": "^1.3.7",
|
||||
"phpunit/phpunit": "^9.6.17",
|
||||
"shipmonk/composer-dependency-analyser": "^1.7",
|
||||
"symfony/browser-kit": "^5.4.35",
|
||||
"symfony/css-selector": "^5.4.35",
|
||||
"symfony/debug-bundle": "^5.4.35",
|
||||
"symfony/maker-bundle": "^1.43",
|
||||
|
|
751
composer.lock
generated
751
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1f0877b1f0f7fc3b074786b51d772cb6",
|
||||
"content-hash": "a85056bec7fa90b9be4aa16c34464c0e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "babdev/pagerfanta-bundle",
|
||||
|
@ -2980,63 +2980,6 @@
|
|||
},
|
||||
"time": "2015-05-14T08:18:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "5.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle.git",
|
||||
"reference": "b87eda7a7162f95574032da17e9323c9899cb6b2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b87eda7a7162f95574032da17e9323c9899cb6b2",
|
||||
"reference": "b87eda7a7162f95574032da17e9323c9899cb6b2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/ringphp": "^1.1",
|
||||
"php": ">=5.4.0",
|
||||
"react/promise": "^2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"phpunit/phpunit": "^4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
|
||||
"homepage": "http://guzzlephp.org/",
|
||||
"keywords": [
|
||||
"client",
|
||||
"curl",
|
||||
"framework",
|
||||
"http",
|
||||
"http client",
|
||||
"rest",
|
||||
"web service"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||
"source": "https://github.com/guzzle/guzzle/tree/5.3"
|
||||
},
|
||||
"time": "2019-10-30T09:32:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "2.7.0",
|
||||
|
@ -3153,117 +3096,6 @@
|
|||
],
|
||||
"time": "2024-07-18T11:15:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/ringphp",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/RingPHP.git",
|
||||
"reference": "5e2a174052995663dd68e6b5ad838afd47dd615b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/RingPHP/zipball/5e2a174052995663dd68e6b5ad838afd47dd615b",
|
||||
"reference": "5e2a174052995663dd68e6b5ad838afd47dd615b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/streams": "~3.0",
|
||||
"php": ">=5.4.0",
|
||||
"react/promise": "~2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": "Guzzle will use specific adapters if cURL is present"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Ring\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.",
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/RingPHP/issues",
|
||||
"source": "https://github.com/guzzle/RingPHP/tree/1.1.1"
|
||||
},
|
||||
"abandoned": true,
|
||||
"time": "2018-07-31T13:22:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/streams",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/streams.git",
|
||||
"reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
|
||||
"reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Stream\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"description": "Provides a simple abstraction over streams of data",
|
||||
"homepage": "http://guzzlephp.org/",
|
||||
"keywords": [
|
||||
"Guzzle",
|
||||
"stream"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/streams/issues",
|
||||
"source": "https://github.com/guzzle/streams/tree/master"
|
||||
},
|
||||
"abandoned": true,
|
||||
"time": "2014-10-12T19:18:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hoa/compiler",
|
||||
"version": "3.17.08.08",
|
||||
|
@ -6511,74 +6343,6 @@
|
|||
},
|
||||
"time": "2024-10-02T11:20:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/guzzle5-adapter",
|
||||
"version": "2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/guzzle5-adapter.git",
|
||||
"reference": "cce48360b1f8a3467bd94e853e6107aa4532008e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/guzzle5-adapter/zipball/cce48360b1f8a3467bd94e853e6107aa4532008e",
|
||||
"reference": "cce48360b1f8a3467bd94e853e6107aa4532008e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^5.1",
|
||||
"php": "^7.0",
|
||||
"php-http/discovery": "^1.0",
|
||||
"php-http/httplug": "^2.0"
|
||||
},
|
||||
"provide": {
|
||||
"php-http/client-implementation": "1.0",
|
||||
"psr/http-client-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"guzzlehttp/ringphp": "^1.1",
|
||||
"php-http/client-integration-tests": "^2.0",
|
||||
"phpunit/phpunit": "^6.0 || ^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Adapter\\Guzzle5\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eric GELOEN",
|
||||
"email": "geloen.eric@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Guzzle 5 HTTP Adapter",
|
||||
"homepage": "http://httplug.io",
|
||||
"keywords": [
|
||||
"Guzzle",
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/guzzle5-adapter/issues",
|
||||
"source": "https://github.com/php-http/guzzle5-adapter/tree/2.0.0"
|
||||
},
|
||||
"abandoned": "php-http/guzzle7-adapter",
|
||||
"time": "2019-02-05T12:28:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/httplug",
|
||||
"version": "2.4.1",
|
||||
|
@ -6636,169 +6400,6 @@
|
|||
},
|
||||
"time": "2024-09-23T11:39:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/httplug-bundle",
|
||||
"version": "1.34.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/HttplugBundle.git",
|
||||
"reference": "87c61d27c025dd9d699a2208a6d06be58061e433"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/HttplugBundle/zipball/87c61d27c025dd9d699a2208a6d06be58061e433",
|
||||
"reference": "87c61d27c025dd9d699a2208a6d06be58061e433",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ^8.0",
|
||||
"php-http/client-common": "^1.9 || ^2.0",
|
||||
"php-http/client-implementation": "^1.0",
|
||||
"php-http/discovery": "^1.14",
|
||||
"php-http/httplug": "^2.0",
|
||||
"php-http/logger-plugin": "^1.1",
|
||||
"php-http/message": "^1.13",
|
||||
"php-http/message-factory": "^1.0.2",
|
||||
"php-http/stopwatch-plugin": "^1.2",
|
||||
"psr/http-message": "^1.0 || ^2.0",
|
||||
"symfony/config": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/event-dispatcher": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/http-kernel": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/options-resolver": "^4.4 || ^5.0 || ^6.0 || ^7.0"
|
||||
},
|
||||
"conflict": {
|
||||
"php-http/cache-plugin": "<1.7.0",
|
||||
"php-http/curl-client": "<2.0",
|
||||
"php-http/guzzle6-adapter": "<1.1",
|
||||
"php-http/socket-client": "<2.0",
|
||||
"php-http/throttle-plugin": "<1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/psr7": "^1.7 || ^2.0",
|
||||
"matthiasnoback/symfony-config-test": "^4.3 || ^5.0",
|
||||
"matthiasnoback/symfony-dependency-injection-test": "^4.3.1 || ^5.0",
|
||||
"nyholm/nsa": "^1.1",
|
||||
"nyholm/psr7": "^1.2.1",
|
||||
"php-http/cache-plugin": "^1.7",
|
||||
"php-http/mock-client": "^1.2",
|
||||
"php-http/promise": "^1.0",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"symfony/browser-kit": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/cache": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/dom-crawler": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/framework-bundle": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/http-foundation": "^4.4.19 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/stopwatch": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/twig-bundle": "^4.4 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/web-profiler-bundle": "^4.4.19 || ^5.0 || ^6.0 || ^7.0",
|
||||
"twig/twig": "^1.41 || ^2.10 || ^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"php-http/cache-plugin": "To configure clients that cache responses",
|
||||
"php-http/mock-client": "Add this to your require-dev section to mock HTTP responses easily",
|
||||
"twig/twig": "Add this to your require-dev section when using the WebProfilerBundle"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\HttplugBundle\\": "src/"
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/Resources/MyPsr18TestClient.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Buchmann",
|
||||
"email": "mail@davidbu.ch"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Symfony integration for HTTPlug",
|
||||
"homepage": "http://httplug.io",
|
||||
"keywords": [
|
||||
"adapter",
|
||||
"bundle",
|
||||
"discovery",
|
||||
"factory",
|
||||
"http",
|
||||
"httplug",
|
||||
"message",
|
||||
"php-http"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/HttplugBundle/issues",
|
||||
"source": "https://github.com/php-http/HttplugBundle/tree/1.34.3"
|
||||
},
|
||||
"time": "2024-09-01T08:25:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/logger-plugin",
|
||||
"version": "1.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/logger-plugin.git",
|
||||
"reference": "bf47eb5cb379962d276c94da14861669c2313563"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/logger-plugin/zipball/bf47eb5cb379962d276c94da14861669c2313563",
|
||||
"reference": "bf47eb5cb379962d276c94da14861669c2313563",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.0 || ^8.0",
|
||||
"php-http/client-common": "^1.9 || ^2.0",
|
||||
"php-http/message": "^1.0",
|
||||
"psr/log": "^1.0 || ^2 || ^3",
|
||||
"symfony/polyfill-php73": "^1.17"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "^5.1 || ^6.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Client\\Common\\Plugin\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "PSR-3 Logger plugin for HTTPlug",
|
||||
"homepage": "http://httplug.io",
|
||||
"keywords": [
|
||||
"http",
|
||||
"httplug",
|
||||
"logger",
|
||||
"plugin"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/logger-plugin/issues",
|
||||
"source": "https://github.com/php-http/logger-plugin/tree/1.3.1"
|
||||
},
|
||||
"time": "2024-09-01T06:51:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/message",
|
||||
"version": "1.16.2",
|
||||
|
@ -6975,64 +6576,6 @@
|
|||
},
|
||||
"time": "2024-03-15T13:55:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/stopwatch-plugin",
|
||||
"version": "1.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/stopwatch-plugin.git",
|
||||
"reference": "11862cfbc719afade4ff407964ab3fbfe9ec2baa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/stopwatch-plugin/zipball/11862cfbc719afade4ff407964ab3fbfe9ec2baa",
|
||||
"reference": "11862cfbc719afade4ff407964ab3fbfe9ec2baa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ^8.0",
|
||||
"php-http/client-common": "^1.9 || ^2.0",
|
||||
"symfony/stopwatch": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/psr7": "^2.1",
|
||||
"symfony/phpunit-bridge": "^6.4.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Client\\Common\\Plugin\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Stopwatch plugin for HTTPlug",
|
||||
"homepage": "http://httplug.io",
|
||||
"keywords": [
|
||||
"http",
|
||||
"httplug",
|
||||
"plugin",
|
||||
"stopwatch"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/stopwatch-plugin/issues",
|
||||
"source": "https://github.com/php-http/stopwatch-plugin/tree/1.4.2"
|
||||
},
|
||||
"time": "2023-12-05T14:36:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "2.2.0",
|
||||
|
@ -8126,78 +7669,6 @@
|
|||
},
|
||||
"time": "2019-03-08T08:55:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/promise",
|
||||
"version": "v2.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/promise.git",
|
||||
"reference": "1a8460931ea36dc5c76838fec5734d55c88c6831"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/promise/zipball/1a8460931ea36dc5c76838fec5734d55c88c6831",
|
||||
"reference": "1a8460931ea36dc5c76838fec5734d55c88c6831",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"React\\Promise\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
|
||||
"keywords": [
|
||||
"promise",
|
||||
"promises"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/promise/issues",
|
||||
"source": "https://github.com/reactphp/promise/tree/v2.11.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-16T16:16:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rulerz-php/doctrine-orm",
|
||||
"version": "dev-master",
|
||||
|
@ -9325,6 +8796,78 @@
|
|||
],
|
||||
"time": "2024-10-22T13:05:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v5.4.45",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/browser-kit.git",
|
||||
"reference": "03cce39764429e07fbab9b989a1182a24578341d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/03cce39764429e07fbab9b989a1182a24578341d",
|
||||
"reference": "03cce39764429e07fbab9b989a1182a24578341d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"symfony/dom-crawler": "^4.4|^5.0|^6.0",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/css-selector": "^4.4|^5.0|^6.0",
|
||||
"symfony/http-client": "^4.4|^5.0|^6.0",
|
||||
"symfony/mime": "^4.4|^5.0|^6.0",
|
||||
"symfony/process": "^4.4|^5.0|^6.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/process": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\BrowserKit\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/browser-kit/tree/v5.4.45"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-22T13:05:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/cache",
|
||||
"version": "v5.4.46",
|
||||
|
@ -18533,6 +18076,78 @@
|
|||
],
|
||||
"time": "2023-11-13T13:48:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/promise",
|
||||
"version": "v2.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/promise.git",
|
||||
"reference": "1a8460931ea36dc5c76838fec5734d55c88c6831"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/promise/zipball/1a8460931ea36dc5c76838fec5734d55c88c6831",
|
||||
"reference": "1a8460931ea36dc5c76838fec5734d55c88c6831",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"React\\Promise\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
|
||||
"keywords": [
|
||||
"promise",
|
||||
"promises"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/promise/issues",
|
||||
"source": "https://github.com/reactphp/promise/tree/v2.11.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-16T16:16:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/socket",
|
||||
"version": "v1.16.0",
|
||||
|
@ -19720,78 +19335,6 @@
|
|||
},
|
||||
"time": "2024-12-30T12:31:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v5.4.45",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/browser-kit.git",
|
||||
"reference": "03cce39764429e07fbab9b989a1182a24578341d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/03cce39764429e07fbab9b989a1182a24578341d",
|
||||
"reference": "03cce39764429e07fbab9b989a1182a24578341d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"symfony/dom-crawler": "^4.4|^5.0|^6.0",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/css-selector": "^4.4|^5.0|^6.0",
|
||||
"symfony/http-client": "^4.4|^5.0|^6.0",
|
||||
"symfony/mime": "^4.4|^5.0|^6.0",
|
||||
"symfony/process": "^4.4|^5.0|^6.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/process": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\BrowserKit\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/browser-kit/tree/v5.4.45"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-22T13:05:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v5.4.45",
|
||||
|
@ -20407,9 +19950,9 @@
|
|||
"ext-tokenizer": "*",
|
||||
"ext-xml": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-dev": {},
|
||||
"platform-overrides": {
|
||||
"php": "7.4.29"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\Guzzle;
|
||||
|
||||
use GuzzleHttp\Event\BeforeEvent;
|
||||
use GuzzleHttp\Event\CompleteEvent;
|
||||
use GuzzleHttp\Event\SubscriberInterface;
|
||||
use GuzzleHttp\Message\RequestInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
use Wallabag\SiteConfig\LoginFormAuthenticator;
|
||||
use Wallabag\SiteConfig\SiteConfig;
|
||||
use Wallabag\SiteConfig\SiteConfigBuilder;
|
||||
|
||||
class AuthenticatorSubscriber implements SubscriberInterface, LoggerAwareInterface
|
||||
{
|
||||
// avoid loop when login failed which can just be a bad login/password
|
||||
// after 2 attempts, we skip the login
|
||||
public const MAX_RETRIES = 2;
|
||||
private int $retries = 0;
|
||||
|
||||
/** @var SiteConfigBuilder */
|
||||
private $configBuilder;
|
||||
|
||||
/** @var LoginFormAuthenticator */
|
||||
private $authenticator;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* AuthenticatorSubscriber constructor.
|
||||
*/
|
||||
public function __construct(SiteConfigBuilder $configBuilder, LoginFormAuthenticator $authenticator)
|
||||
{
|
||||
$this->configBuilder = $configBuilder;
|
||||
$this->authenticator = $authenticator;
|
||||
$this->logger = new NullLogger();
|
||||
}
|
||||
|
||||
public function setLogger(LoggerInterface $logger): void
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function getEvents(): array
|
||||
{
|
||||
return [
|
||||
'before' => ['loginIfRequired'],
|
||||
'complete' => ['loginIfRequested'],
|
||||
];
|
||||
}
|
||||
|
||||
public function loginIfRequired(BeforeEvent $event)
|
||||
{
|
||||
$config = $this->buildSiteConfig($event->getRequest());
|
||||
if (false === $config || !$config->requiresLogin()) {
|
||||
$this->logger->debug('loginIfRequired> will not require login');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$client = $event->getClient();
|
||||
|
||||
if (!$this->authenticator->isLoggedIn($config, $client)) {
|
||||
$this->logger->debug('loginIfRequired> user is not logged in, attach authenticator');
|
||||
|
||||
$emitter = $client->getEmitter();
|
||||
$emitter->detach($this);
|
||||
$this->authenticator->login($config, $client);
|
||||
$emitter->attach($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function loginIfRequested(CompleteEvent $event)
|
||||
{
|
||||
$config = $this->buildSiteConfig($event->getRequest());
|
||||
if (false === $config || !$config->requiresLogin()) {
|
||||
$this->logger->debug('loginIfRequested> will not require login');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$body = $event->getResponse()->getBody();
|
||||
|
||||
if (
|
||||
null === $body
|
||||
|| '' === $body->getContents()
|
||||
) {
|
||||
$this->logger->debug('loginIfRequested> empty body, ignoring');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$isLoginRequired = $this->authenticator->isLoginRequired($config, $body);
|
||||
|
||||
$this->logger->debug('loginIfRequested> retry #' . $this->retries . ' with login ' . ($isLoginRequired ? '' : 'not ') . 'required');
|
||||
|
||||
if ($isLoginRequired && $this->retries < self::MAX_RETRIES) {
|
||||
$client = $event->getClient();
|
||||
|
||||
$emitter = $client->getEmitter();
|
||||
$emitter->detach($this);
|
||||
$this->authenticator->login($config, $client);
|
||||
$emitter->attach($this);
|
||||
|
||||
$event->retry();
|
||||
|
||||
++$this->retries;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SiteConfig|false
|
||||
*/
|
||||
private function buildSiteConfig(RequestInterface $request)
|
||||
{
|
||||
return $this->configBuilder->buildForHost($request->getHost());
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\Helper;
|
||||
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Event\SubscriberInterface;
|
||||
use Http\Adapter\Guzzle5\Client as GuzzleAdapter;
|
||||
use Http\Client\HttpClient;
|
||||
use Http\HttplugBundle\ClientFactory\ClientFactory;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Builds and configures the HTTP client.
|
||||
*/
|
||||
class HttpClientFactory implements ClientFactory
|
||||
{
|
||||
/** @var SubscriberInterface[] */
|
||||
private $subscribers = [];
|
||||
|
||||
/** @var CookieJar */
|
||||
private $cookieJar;
|
||||
|
||||
private $restrictedAccess;
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* HttpClientFactory constructor.
|
||||
*
|
||||
* @param string $restrictedAccess This param is a kind of boolean. Values: 0 or 1
|
||||
*/
|
||||
public function __construct(CookieJar $cookieJar, $restrictedAccess, LoggerInterface $logger)
|
||||
{
|
||||
$this->cookieJar = $cookieJar;
|
||||
$this->restrictedAccess = $restrictedAccess;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a subscriber to the HTTP client.
|
||||
*/
|
||||
public function addSubscriber(SubscriberInterface $subscriber)
|
||||
{
|
||||
$this->subscribers[] = $subscriber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Input an array of configuration to be able to create a HttpClient.
|
||||
*
|
||||
* @return HttpClient
|
||||
*/
|
||||
public function createClient(array $config = [])
|
||||
{
|
||||
$this->logger->log('debug', 'Restricted access config enabled?', ['enabled' => (int) $this->restrictedAccess]);
|
||||
|
||||
if (0 === (int) $this->restrictedAccess) {
|
||||
return new GuzzleAdapter(new GuzzleClient($config));
|
||||
}
|
||||
|
||||
// we clear the cookie to avoid websites who use cookies for analytics
|
||||
$this->cookieJar->clear();
|
||||
if (!isset($config['defaults']['cookies'])) {
|
||||
// need to set the (shared) cookie jar
|
||||
$config['defaults']['cookies'] = $this->cookieJar;
|
||||
}
|
||||
|
||||
$guzzle = new GuzzleClient($config);
|
||||
foreach ($this->subscribers as $subscriber) {
|
||||
$guzzle->getEmitter()->attach($subscriber);
|
||||
}
|
||||
|
||||
return new GuzzleAdapter($guzzle);
|
||||
}
|
||||
}
|
95
src/HttpClient/Authenticator.php
Normal file
95
src/HttpClient/Authenticator.php
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\HttpClient;
|
||||
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use Wallabag\SiteConfig\LoginFormAuthenticator;
|
||||
use Wallabag\SiteConfig\SiteConfig;
|
||||
use Wallabag\SiteConfig\SiteConfigBuilder;
|
||||
|
||||
class Authenticator implements LoggerAwareInterface
|
||||
{
|
||||
/** @var SiteConfigBuilder */
|
||||
private $configBuilder;
|
||||
|
||||
/** @var LoginFormAuthenticator */
|
||||
private $authenticator;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
public function __construct(SiteConfigBuilder $configBuilder, LoginFormAuthenticator $authenticator)
|
||||
{
|
||||
$this->configBuilder = $configBuilder;
|
||||
$this->authenticator = $authenticator;
|
||||
$this->logger = new NullLogger();
|
||||
}
|
||||
|
||||
public function setLogger(LoggerInterface $logger): void
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function loginIfRequired(string $url): bool
|
||||
{
|
||||
$config = $this->buildSiteConfig(new Uri($url));
|
||||
if (false === $config || !$config->requiresLogin()) {
|
||||
$this->logger->debug('loginIfRequired> will not require login');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->authenticator->isLoggedIn($config)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->logger->debug('loginIfRequired> user is not logged in, attach authenticator');
|
||||
|
||||
$this->authenticator->login($config);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function loginIfRequested(ResponseInterface $response): bool
|
||||
{
|
||||
$config = $this->buildSiteConfig(new Uri($response->getInfo('url')));
|
||||
if (false === $config || !$config->requiresLogin()) {
|
||||
$this->logger->debug('loginIfRequested> will not require login');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = $response->getContent();
|
||||
|
||||
if ('' === $body) {
|
||||
$this->logger->debug('loginIfRequested> empty body, ignoring');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$isLoginRequired = $this->authenticator->isLoginRequired($config, $body);
|
||||
|
||||
$this->logger->debug('loginIfRequested> retry with login ' . ($isLoginRequired ? '' : 'not ') . 'required');
|
||||
|
||||
if (!$isLoginRequired) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->authenticator->login($config);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SiteConfig|false
|
||||
*/
|
||||
private function buildSiteConfig(UriInterface $uri)
|
||||
{
|
||||
return $this->configBuilder->buildForHost($uri->getHost());
|
||||
}
|
||||
}
|
84
src/HttpClient/WallabagClient.php
Normal file
84
src/HttpClient/WallabagClient.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\HttpClient;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
|
||||
|
||||
class WallabagClient implements HttpClientInterface
|
||||
{
|
||||
private $restrictedAccess;
|
||||
private HttpClientInterface $httpClient;
|
||||
private HttpBrowser $browser;
|
||||
private Authenticator $authenticator;
|
||||
private LoggerInterface $logger;
|
||||
|
||||
public function __construct($restrictedAccess, HttpBrowser $browser, Authenticator $authenticator, LoggerInterface $logger)
|
||||
{
|
||||
$this->restrictedAccess = $restrictedAccess;
|
||||
$this->browser = $browser;
|
||||
$this->authenticator = $authenticator;
|
||||
$this->logger = $logger;
|
||||
|
||||
$this->httpClient = HttpClient::create([
|
||||
'timeout' => 10,
|
||||
]);
|
||||
}
|
||||
|
||||
public function request(string $method, string $url, array $options = []): ResponseInterface
|
||||
{
|
||||
$this->logger->log('debug', 'Restricted access config enabled?', ['enabled' => (int) $this->restrictedAccess]);
|
||||
|
||||
if (0 === (int) $this->restrictedAccess) {
|
||||
return $this->httpClient->request($method, $url, $options);
|
||||
}
|
||||
|
||||
$login = $this->authenticator->loginIfRequired($url);
|
||||
|
||||
if (!$login) {
|
||||
return $this->httpClient->request($method, $url, $options);
|
||||
}
|
||||
|
||||
if (null !== $cookieHeader = $this->getCookieHeader($url)) {
|
||||
$options['headers']['cookie'] = $cookieHeader;
|
||||
}
|
||||
|
||||
$response = $this->httpClient->request($method, $url, $options);
|
||||
|
||||
$login = $this->authenticator->loginIfRequested($response);
|
||||
|
||||
if (!$login) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (null !== $cookieHeader = $this->getCookieHeader($url)) {
|
||||
$options['headers']['cookie'] = $cookieHeader;
|
||||
}
|
||||
|
||||
return $this->httpClient->request($method, $url, $options);
|
||||
}
|
||||
|
||||
public function stream($responses, ?float $timeout = null): ResponseStreamInterface
|
||||
{
|
||||
return $this->httpClient->stream($responses, $timeout);
|
||||
}
|
||||
|
||||
private function getCookieHeader(string $url): ?string
|
||||
{
|
||||
$cookies = [];
|
||||
|
||||
foreach ($this->browser->getCookieJar()->allRawValues($url) as $name => $value) {
|
||||
$cookies[] = $name . '=' . $value;
|
||||
}
|
||||
|
||||
if ([] === $cookies) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return implode('; ', $cookies);
|
||||
}
|
||||
}
|
|
@ -2,18 +2,19 @@
|
|||
|
||||
namespace Wallabag\SiteConfig;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||
use Wallabag\ExpressionLanguage\AuthenticatorProvider;
|
||||
|
||||
class LoginFormAuthenticator
|
||||
{
|
||||
private HttpBrowser $browser;
|
||||
private ExpressionLanguage $expressionLanguage;
|
||||
|
||||
public function __construct(AuthenticatorProvider $authenticatorProvider)
|
||||
public function __construct(HttpBrowser $browser, AuthenticatorProvider $authenticatorProvider)
|
||||
{
|
||||
$this->browser = $browser;
|
||||
$this->expressionLanguage = new ExpressionLanguage(null, [$authenticatorProvider]);
|
||||
}
|
||||
|
||||
|
@ -22,17 +23,14 @@ class LoginFormAuthenticator
|
|||
*
|
||||
* @return self
|
||||
*/
|
||||
public function login(SiteConfig $siteConfig, ClientInterface $guzzle)
|
||||
public function login(SiteConfig $siteConfig)
|
||||
{
|
||||
$postFields = [
|
||||
$siteConfig->getUsernameField() => $siteConfig->getUsername(),
|
||||
$siteConfig->getPasswordField() => $siteConfig->getPassword(),
|
||||
] + $this->getExtraFields($siteConfig);
|
||||
|
||||
$guzzle->post(
|
||||
$siteConfig->getLoginUri(),
|
||||
['body' => $postFields, 'allow_redirects' => true, 'verify' => false]
|
||||
);
|
||||
$this->browser->request('POST', $siteConfig->getLoginUri(), $postFields);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -42,17 +40,14 @@ class LoginFormAuthenticator
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLoggedIn(SiteConfig $siteConfig, ClientInterface $guzzle)
|
||||
public function isLoggedIn(SiteConfig $siteConfig)
|
||||
{
|
||||
if (($cookieJar = $guzzle->getDefaultOption('cookies')) instanceof CookieJar) {
|
||||
/** @var \GuzzleHttp\Cookie\SetCookie $cookie */
|
||||
foreach ($cookieJar as $cookie) {
|
||||
foreach ($this->browser->getCookieJar()->all() as $cookie) {
|
||||
// check required cookies
|
||||
if ($cookie->getDomain() === $siteConfig->getHost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,314 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Wallabag\Guzzle;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Event\BeforeEvent;
|
||||
use GuzzleHttp\Event\CompleteEvent;
|
||||
use GuzzleHttp\Message\Request;
|
||||
use GuzzleHttp\Message\Response;
|
||||
use GuzzleHttp\Stream\Stream;
|
||||
use GuzzleHttp\Subscriber\Mock;
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Monolog\Logger;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Wallabag\Guzzle\AuthenticatorSubscriber;
|
||||
use Wallabag\SiteConfig\ArraySiteConfigBuilder;
|
||||
use Wallabag\SiteConfig\LoginFormAuthenticator;
|
||||
|
||||
class AuthenticatorSubscriberTest extends TestCase
|
||||
{
|
||||
public function testGetEvents()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$subscriber = new AuthenticatorSubscriber(
|
||||
new ArraySiteConfigBuilder(),
|
||||
$authenticator
|
||||
);
|
||||
$events = $subscriber->getEvents();
|
||||
|
||||
$this->assertArrayHasKey('before', $events);
|
||||
$this->assertArrayHasKey('complete', $events);
|
||||
$this->assertSame('loginIfRequired', $events['before'][0]);
|
||||
$this->assertSame('loginIfRequested', $events['complete'][0]);
|
||||
}
|
||||
|
||||
public function testLoginIfRequiredNotRequired()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => []]);
|
||||
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$request = new Request('GET', 'http://www.example.com');
|
||||
|
||||
$event = $this->getMockBuilder(BeforeEvent::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request);
|
||||
|
||||
$subscriber->loginIfRequired($event);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequired> will not require login', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequiredWithNotLoggedInUser()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('isLoggedIn')
|
||||
->willReturn(false);
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('login');
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => ['requiresLogin' => true]]);
|
||||
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$response = new Response(
|
||||
200,
|
||||
['content-type' => 'text/html'],
|
||||
Stream::factory('')
|
||||
);
|
||||
$guzzle = new Client();
|
||||
$guzzle->getEmitter()->attach(new Mock([$response]));
|
||||
|
||||
$request = new Request('GET', 'http://www.example.com');
|
||||
|
||||
$event = $this->getMockBuilder(BeforeEvent::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request);
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getClient')
|
||||
->willReturn($guzzle);
|
||||
|
||||
$subscriber->loginIfRequired($event);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequired> user is not logged in, attach authenticator', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequestedNotRequired()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => []]);
|
||||
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$request = new Request('GET', 'http://www.example.com');
|
||||
|
||||
$event = $this->getMockBuilder(CompleteEvent::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request);
|
||||
|
||||
$subscriber->loginIfRequested($event);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequested> will not require login', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequestedNotRequested()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('isLoginRequired')
|
||||
->willReturn(false);
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => [
|
||||
'requiresLogin' => true,
|
||||
'notLoggedInXpath' => '//html',
|
||||
]]);
|
||||
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$response = new Response(
|
||||
200,
|
||||
['content-type' => 'text/html'],
|
||||
Stream::factory('<html><body/></html>')
|
||||
);
|
||||
$request = new Request('GET', 'http://www.example.com');
|
||||
|
||||
$event = $this->getMockBuilder(CompleteEvent::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getResponse')
|
||||
->willReturn($response);
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request);
|
||||
|
||||
$subscriber->loginIfRequested($event);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequested> retry #0 with login not required', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequestedRequested()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('isLoginRequired')
|
||||
->willReturn(true);
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('login');
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => [
|
||||
'requiresLogin' => true,
|
||||
'notLoggedInXpath' => '//html',
|
||||
]]);
|
||||
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$response = new Response(
|
||||
200,
|
||||
['content-type' => 'text/html'],
|
||||
Stream::factory('<html><body/></html>')
|
||||
);
|
||||
$guzzle = new Client();
|
||||
$guzzle->getEmitter()->attach(new Mock([$response]));
|
||||
$request = new Request('GET', 'http://www.example.com');
|
||||
|
||||
$event = $this->getMockBuilder(CompleteEvent::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getResponse')
|
||||
->willReturn($response);
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request);
|
||||
|
||||
$event->expects($this->any())
|
||||
->method('getClient')
|
||||
->willReturn($guzzle);
|
||||
|
||||
$subscriber->loginIfRequested($event);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequested> retry #0 with login required', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequestedRedirect()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => [
|
||||
'requiresLogin' => true,
|
||||
'notLoggedInXpath' => '//html',
|
||||
]]);
|
||||
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$response = new Response(
|
||||
301,
|
||||
[],
|
||||
Stream::factory('')
|
||||
);
|
||||
$guzzle = new Client();
|
||||
$guzzle->getEmitter()->attach(new Mock([$response]));
|
||||
$request = new Request('GET', 'http://www.example.com');
|
||||
|
||||
$event = $this->getMockBuilder(CompleteEvent::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getResponse')
|
||||
->willReturn($response);
|
||||
|
||||
$event->expects($this->once())
|
||||
->method('getRequest')
|
||||
->willReturn($request);
|
||||
|
||||
$event->expects($this->any())
|
||||
->method('getClient')
|
||||
->willReturn($guzzle);
|
||||
|
||||
$subscriber->loginIfRequested($event);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequested> empty body, ignoring', $records[0]['message']);
|
||||
}
|
||||
}
|
|
@ -2,13 +2,12 @@
|
|||
|
||||
namespace Tests\Wallabag\SiteConfig;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Message\Response;
|
||||
use GuzzleHttp\Stream\Stream;
|
||||
use GuzzleHttp\Subscriber\Mock;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\HttpClient\MockHttpClient;
|
||||
use Symfony\Component\HttpClient\Response\MockResponse;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use Wallabag\ExpressionLanguage\AuthenticatorProvider;
|
||||
use Wallabag\SiteConfig\LoginFormAuthenticator;
|
||||
use Wallabag\SiteConfig\SiteConfig;
|
||||
|
@ -17,16 +16,6 @@ class LoginFormAuthenticatorTest extends TestCase
|
|||
{
|
||||
public function testLoginPost()
|
||||
{
|
||||
$response = new Response(
|
||||
200,
|
||||
['content-type' => 'text/html'],
|
||||
Stream::factory('')
|
||||
);
|
||||
$guzzle = new Client();
|
||||
$guzzle->getEmitter()->attach(new Mock([$response]));
|
||||
|
||||
$mockHttpClient = new MockHttpClient([new MockResponse('', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']])]);
|
||||
|
||||
$siteConfig = new SiteConfig([
|
||||
'host' => 'example.com',
|
||||
'loginUri' => 'http://example.com/login',
|
||||
|
@ -40,25 +29,23 @@ class LoginFormAuthenticatorTest extends TestCase
|
|||
'password' => 'unkn0wn',
|
||||
]);
|
||||
|
||||
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient);
|
||||
$auth = new LoginFormAuthenticator($authenticatorProvider);
|
||||
$res = $auth->login($siteConfig, $guzzle);
|
||||
$browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
|
||||
$browserClient = new MockHttpClient([$browserResponse]);
|
||||
$browser = new HttpBrowser($browserClient);
|
||||
|
||||
$requestHtmlFunctionResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
|
||||
$requestHtmlFunctionClient = new MockHttpClient([$requestHtmlFunctionResponse]);
|
||||
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
|
||||
|
||||
$auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
|
||||
|
||||
$res = $auth->login($siteConfig);
|
||||
|
||||
$this->assertInstanceOf(LoginFormAuthenticator::class, $res);
|
||||
}
|
||||
|
||||
public function testLoginPostWithExtraFieldsButEmptyHtml()
|
||||
{
|
||||
$response = new Response(
|
||||
200,
|
||||
['content-type' => 'text/html'],
|
||||
Stream::factory('<html></html>')
|
||||
);
|
||||
$guzzle = new Client();
|
||||
$guzzle->getEmitter()->attach(new Mock([$response, $response]));
|
||||
|
||||
$mockHttpClient = new MockHttpClient([new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']])]);
|
||||
|
||||
$siteConfig = new SiteConfig([
|
||||
'host' => 'example.com',
|
||||
'loginUri' => 'http://example.com/login',
|
||||
|
@ -73,9 +60,17 @@ class LoginFormAuthenticatorTest extends TestCase
|
|||
'password' => 'unkn0wn',
|
||||
]);
|
||||
|
||||
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient);
|
||||
$auth = new LoginFormAuthenticator($authenticatorProvider);
|
||||
$res = $auth->login($siteConfig, $guzzle);
|
||||
$browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
|
||||
$browserClient = new MockHttpClient([$browserResponse]);
|
||||
$browser = new HttpBrowser($browserClient);
|
||||
|
||||
$requestHtmlFunctionResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
|
||||
$requestHtmlFunctionClient = new MockHttpClient([$requestHtmlFunctionResponse]);
|
||||
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
|
||||
|
||||
$auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
|
||||
|
||||
$res = $auth->login($siteConfig);
|
||||
|
||||
$this->assertInstanceOf(LoginFormAuthenticator::class, $res);
|
||||
}
|
||||
|
@ -83,49 +78,6 @@ class LoginFormAuthenticatorTest extends TestCase
|
|||
// testing preg_match
|
||||
public function testLoginPostWithExtraFieldsWithRegex()
|
||||
{
|
||||
$response = $this->getMockBuilder(Response::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getBody')
|
||||
->willReturn(file_get_contents(__DIR__ . '/../fixtures/aoc.media.html'));
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->willReturn(200);
|
||||
|
||||
$mockHttpClient = new MockHttpClient([new MockResponse(file_get_contents(__DIR__ . '/../fixtures/aoc.media.html'), ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']])]);
|
||||
|
||||
$client = $this->getMockBuilder(Client::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$client->expects($this->any())
|
||||
->method('post')
|
||||
->with(
|
||||
$this->equalTo('https://aoc.media/wp-admin/admin-ajax.php'),
|
||||
$this->equalTo([
|
||||
'body' => [
|
||||
'nom' => 'johndoe',
|
||||
'password' => 'unkn0wn',
|
||||
'security' => 'c506c1b8bc',
|
||||
'action' => 'login_user',
|
||||
],
|
||||
'allow_redirects' => true,
|
||||
'verify' => false,
|
||||
])
|
||||
)
|
||||
->willReturn($response);
|
||||
|
||||
$client->expects($this->any())
|
||||
->method('get')
|
||||
->with(
|
||||
$this->equalTo('https://aoc.media/'),
|
||||
$this->equalTo([])
|
||||
)
|
||||
->willReturn($response);
|
||||
|
||||
$siteConfig = new SiteConfig([
|
||||
'host' => 'aoc.media',
|
||||
'loginUri' => 'https://aoc.media/wp-admin/admin-ajax.php',
|
||||
|
@ -139,78 +91,44 @@ class LoginFormAuthenticatorTest extends TestCase
|
|||
'password' => 'unkn0wn',
|
||||
]);
|
||||
|
||||
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient);
|
||||
$auth = new LoginFormAuthenticator($authenticatorProvider);
|
||||
$res = $auth->login($siteConfig, $client);
|
||||
|
||||
$this->assertInstanceOf(LoginFormAuthenticator::class, $res);
|
||||
}
|
||||
|
||||
public function testLoginPostWithExtraFieldsWithData()
|
||||
{
|
||||
$response = $this->getMockBuilder(Response::class)
|
||||
->disableOriginalConstructor()
|
||||
$browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
|
||||
$browserClient = new MockHttpClient([$browserResponse]);
|
||||
$browser = $this->getMockBuilder(HttpBrowser::class)
|
||||
->setConstructorArgs([$browserClient])
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getBody')
|
||||
->willReturn(file_get_contents(__DIR__ . '/../fixtures/nextinpact-login.html'));
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->willReturn(200);
|
||||
|
||||
$mockHttpClient = new MockHttpClient([new MockResponse(file_get_contents(__DIR__ . '/../fixtures/nextinpact-login.html'), ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']])]);
|
||||
|
||||
$client = $this->getMockBuilder(Client::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$client->expects($this->any())
|
||||
->method('post')
|
||||
$browser->expects($this->any())
|
||||
->method('request')
|
||||
->with(
|
||||
$this->equalTo('https://compte.nextinpact.com/Account/Login'),
|
||||
$this->equalTo('POST'),
|
||||
$this->equalTo('https://aoc.media/wp-admin/admin-ajax.php'),
|
||||
$this->equalTo([
|
||||
'body' => [
|
||||
'UserName' => 'johndoe',
|
||||
'Password' => 'unkn0wn',
|
||||
'__RequestVerificationToken' => 's6x2QcnQDUL92mkKSi_JuUBXcgUYx_Plf-KyQ2eJypKAjQZIeTvaFHOsfEdTrcSXt3dt2CW39V7r9V16LUtvjszodAU1',
|
||||
'returnUrl' => 'https://www.nextinpact.com/news/102835-pour-cour-comptes-fonctionnement-actuel-vote-par-internet-nest-pas-satisfaisant.htm',
|
||||
],
|
||||
'allow_redirects' => true,
|
||||
'verify' => false,
|
||||
])
|
||||
)
|
||||
->willReturn($response);
|
||||
|
||||
$client->expects($this->any())
|
||||
->method('get')
|
||||
->with(
|
||||
$this->equalTo('https://compte.nextinpact.com/Account/Login?http://www.nextinpact.com/'),
|
||||
$this->equalTo([
|
||||
'headers' => [
|
||||
'X-Requested-With' => 'XMLHttpRequest',
|
||||
],
|
||||
])
|
||||
)
|
||||
->willReturn($response);
|
||||
|
||||
$siteConfig = new SiteConfig([
|
||||
'host' => 'nextinpact.com',
|
||||
'loginUri' => 'https://compte.nextinpact.com/Account/Login',
|
||||
'usernameField' => 'UserName',
|
||||
'passwordField' => 'Password',
|
||||
'extraFields' => [
|
||||
'__RequestVerificationToken' => '@=xpath(\'//form[@action="/Account/Login"]/input[@name="__RequestVerificationToken"]\', request_html(\'https://compte.nextinpact.com/Account/Login?http://www.nextinpact.com/\', {\'headers\': {\'X-Requested-With\':\'XMLHttpRequest\'}}))',
|
||||
'returnUrl' => 'https://www.nextinpact.com/news/102835-pour-cour-comptes-fonctionnement-actuel-vote-par-internet-nest-pas-satisfaisant.htm',
|
||||
],
|
||||
'username' => 'johndoe',
|
||||
'nom' => 'johndoe',
|
||||
'password' => 'unkn0wn',
|
||||
]);
|
||||
'security' => 'c506c1b8bc',
|
||||
'action' => 'login_user',
|
||||
])
|
||||
)
|
||||
;
|
||||
|
||||
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient);
|
||||
$auth = new LoginFormAuthenticator($authenticatorProvider);
|
||||
$res = $auth->login($siteConfig, $client);
|
||||
$requestHtmlFunctionResponse = $this->getMockBuilder(ResponseInterface::class)->getMock();
|
||||
$requestHtmlFunctionResponse->expects($this->any())
|
||||
->method('getContent')
|
||||
->willReturn(file_get_contents(__DIR__ . '/../fixtures/aoc.media.html'))
|
||||
;
|
||||
$requestHtmlFunctionClient = $this->getMockBuilder(HttpClientInterface::class)->getMock();
|
||||
$requestHtmlFunctionClient->expects($this->any())
|
||||
->method('request')
|
||||
->with(
|
||||
$this->equalTo('GET'),
|
||||
$this->equalTo('https://aoc.media/'),
|
||||
)
|
||||
->willReturn($requestHtmlFunctionResponse)
|
||||
;
|
||||
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
|
||||
|
||||
$auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
|
||||
|
||||
$res = $auth->login($siteConfig);
|
||||
|
||||
$this->assertInstanceOf(LoginFormAuthenticator::class, $res);
|
||||
}
|
||||
|
@ -225,10 +143,16 @@ class LoginFormAuthenticatorTest extends TestCase
|
|||
'password' => 'unkn0wn',
|
||||
]);
|
||||
|
||||
$mockHttpClient = new MockHttpClient();
|
||||
$browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
|
||||
$browserClient = new MockHttpClient([$browserResponse]);
|
||||
$browser = new HttpBrowser($browserClient);
|
||||
|
||||
$requestHtmlFunctionResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
|
||||
$requestHtmlFunctionClient = new MockHttpClient([$requestHtmlFunctionResponse]);
|
||||
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
|
||||
|
||||
$auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
|
||||
|
||||
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient);
|
||||
$auth = new LoginFormAuthenticator($authenticatorProvider);
|
||||
$loginRequired = $auth->isLoginRequired($siteConfig, file_get_contents(__DIR__ . '/../fixtures/nextinpact-login.html'));
|
||||
|
||||
$this->assertFalse($loginRequired);
|
||||
|
@ -245,10 +169,16 @@ class LoginFormAuthenticatorTest extends TestCase
|
|||
'notLoggedInXpath' => '//h2[@class="title_reserve_article"]',
|
||||
]);
|
||||
|
||||
$mockHttpClient = new MockHttpClient();
|
||||
$browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
|
||||
$browserClient = new MockHttpClient([$browserResponse]);
|
||||
$browser = new HttpBrowser($browserClient);
|
||||
|
||||
$requestHtmlFunctionResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
|
||||
$requestHtmlFunctionClient = new MockHttpClient([$requestHtmlFunctionResponse]);
|
||||
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
|
||||
|
||||
$auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
|
||||
|
||||
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient);
|
||||
$auth = new LoginFormAuthenticator($authenticatorProvider);
|
||||
$loginRequired = $auth->isLoginRequired($siteConfig, file_get_contents(__DIR__ . '/../fixtures/nextinpact-article.html'));
|
||||
|
||||
$this->assertTrue($loginRequired);
|
||||
|
|
239
tests/Tests/Wallabag/HttpClient/AuthenticatorTest.php
Normal file
239
tests/Tests/Wallabag/HttpClient/AuthenticatorTest.php
Normal file
|
@ -0,0 +1,239 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Wallabag\HttpClient;
|
||||
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Monolog\Logger;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use Wallabag\HttpClient\Authenticator;
|
||||
use Wallabag\SiteConfig\ArraySiteConfigBuilder;
|
||||
use Wallabag\SiteConfig\LoginFormAuthenticator;
|
||||
|
||||
class AuthenticatorTest extends TestCase
|
||||
{
|
||||
public function testLoginIfRequiredNotRequired()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => []]);
|
||||
$subscriber = new Authenticator($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$login = $subscriber->loginIfRequired('http://www.example.com');
|
||||
|
||||
$this->assertFalse($login);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequired> will not require login', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequiredWithNotLoggedInUser()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('isLoggedIn')
|
||||
->willReturn(false);
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('login');
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => ['requiresLogin' => true]]);
|
||||
$subscriber = new Authenticator($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$login = $subscriber->loginIfRequired('http://www.example.com');
|
||||
|
||||
$this->assertTrue($login);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequired> user is not logged in, attach authenticator', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequestedNotRequired()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => []]);
|
||||
$subscriber = new Authenticator($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$response = $this->getMockBuilder(ResponseInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->once())
|
||||
->method('getInfo')
|
||||
->with($this->equalTo('url'))
|
||||
->willReturn('http://www.example.com');
|
||||
|
||||
$login = $subscriber->loginIfRequested($response);
|
||||
|
||||
$this->assertFalse($login);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequested> will not require login', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequestedNotRequested()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('isLoginRequired')
|
||||
->willReturn(false);
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => [
|
||||
'requiresLogin' => true,
|
||||
'notLoggedInXpath' => '//html',
|
||||
]]);
|
||||
$subscriber = new Authenticator($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$response = $this->getMockBuilder(ResponseInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->once())
|
||||
->method('getInfo')
|
||||
->with($this->equalTo('url'))
|
||||
->willReturn('http://www.example.com');
|
||||
|
||||
$response->expects($this->once())
|
||||
->method('getContent')
|
||||
->willReturn('<html><body/></html>');
|
||||
|
||||
$login = $subscriber->loginIfRequested($response);
|
||||
|
||||
$this->assertFalse($login);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequested> retry with login not required', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequestedRequested()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('isLoginRequired')
|
||||
->willReturn(true);
|
||||
|
||||
$authenticator->expects($this->once())
|
||||
->method('login');
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => [
|
||||
'requiresLogin' => true,
|
||||
'notLoggedInXpath' => '//html',
|
||||
]]);
|
||||
$subscriber = new Authenticator($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$response = $this->getMockBuilder(ResponseInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->once())
|
||||
->method('getInfo')
|
||||
->with($this->equalTo('url'))
|
||||
->willReturn('http://www.example.com');
|
||||
|
||||
$response->expects($this->once())
|
||||
->method('getContent')
|
||||
->willReturn('<html><body/></html>');
|
||||
|
||||
$login = $subscriber->loginIfRequested($response);
|
||||
|
||||
$this->assertTrue($login);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequested> retry with login required', $records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLoginIfRequestedRedirect()
|
||||
{
|
||||
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$builder = new ArraySiteConfigBuilder(['example.com' => [
|
||||
'requiresLogin' => true,
|
||||
'notLoggedInXpath' => '//html',
|
||||
]]);
|
||||
$subscriber = new Authenticator($builder, $authenticator);
|
||||
|
||||
$logger = new Logger('foo');
|
||||
$handler = new TestHandler();
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
$subscriber->setLogger($logger);
|
||||
|
||||
$response = $this->getMockBuilder(ResponseInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->once())
|
||||
->method('getInfo')
|
||||
->with($this->equalTo('url'))
|
||||
->willReturn('http://www.example.com');
|
||||
|
||||
$response->expects($this->once())
|
||||
->method('getContent')
|
||||
->willReturn('');
|
||||
|
||||
$login = $subscriber->loginIfRequested($response);
|
||||
|
||||
$this->assertFalse($login);
|
||||
|
||||
$records = $handler->getRecords();
|
||||
|
||||
$this->assertCount(1, $records);
|
||||
$this->assertSame('loginIfRequested> empty body, ignoring', $records[0]['message']);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue