aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJeremy Benoist <j0k3r@users.noreply.github.com>2016-11-22 19:12:53 +0100
committerGitHub <noreply@github.com>2016-11-22 19:12:53 +0100
commit176e0ea3caee9f4eccc1ddda5f84b14da2cca034 (patch)
tree543ff69ee6b56c6383f3f9758221fc64154dee5c
parent1d5dd2c2410d7866752bca5d65886afc6a7650ef (diff)
parentd51093a7d964ca720793d0cfcf4af601f2de448a (diff)
downloadwallabag-176e0ea3caee9f4eccc1ddda5f84b14da2cca034.tar.gz
wallabag-176e0ea3caee9f4eccc1ddda5f84b14da2cca034.tar.zst
wallabag-176e0ea3caee9f4eccc1ddda5f84b14da2cca034.zip
Merge pull request #2317 from wallabag/restricted-access
Added authentication for restricted access articles
-rw-r--r--app/AppKernel.php1
-rw-r--r--app/DoctrineMigrations/Version20161122144743.php45
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pt.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml1
-rw-r--r--app/Resources/CraueConfigBundle/translations/CraueConfigBundle.tr.yml1
-rw-r--r--app/config/parameters.yml.dist3
-rw-r--r--composer.json3
-rw-r--r--docs/de/developer/paywall.rst56
-rw-r--r--docs/de/index.rst1
-rw-r--r--docs/en/developer/paywall.rst56
-rw-r--r--docs/en/index.rst1
-rw-r--r--docs/fr/developer/paywall.rst56
-rw-r--r--docs/fr/index.rst1
-rw-r--r--src/Wallabag/CoreBundle/Command/InstallCommand.php5
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php5
-rw-r--r--src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php68
-rw-r--r--src/Wallabag/CoreBundle/Helper/HttpClientFactory.php54
-rw-r--r--src/Wallabag/CoreBundle/Resources/config/services.yml33
-rw-r--r--tests/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilderTest.php85
28 files changed, 484 insertions, 1 deletions
diff --git a/app/AppKernel.php b/app/AppKernel.php
index 81b83ef9..c8382d5f 100644
--- a/app/AppKernel.php
+++ b/app/AppKernel.php
@@ -31,6 +31,7 @@ class AppKernel extends Kernel
31 new Craue\ConfigBundle\CraueConfigBundle(), 31 new Craue\ConfigBundle\CraueConfigBundle(),
32 new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(), 32 new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
33 new FOS\JsRoutingBundle\FOSJsRoutingBundle(), 33 new FOS\JsRoutingBundle\FOSJsRoutingBundle(),
34 new BD\GuzzleSiteAuthenticatorBundle\BDGuzzleSiteAuthenticatorBundle(),
34 35
35 // wallabag bundles 36 // wallabag bundles
36 new Wallabag\CoreBundle\WallabagCoreBundle(), 37 new Wallabag\CoreBundle\WallabagCoreBundle(),
diff --git a/app/DoctrineMigrations/Version20161122144743.php b/app/DoctrineMigrations/Version20161122144743.php
new file mode 100644
index 00000000..ec80c48e
--- /dev/null
+++ b/app/DoctrineMigrations/Version20161122144743.php
@@ -0,0 +1,45 @@
1<?php
2
3namespace Application\Migrations;
4
5use Doctrine\DBAL\Migrations\AbstractMigration;
6use Doctrine\DBAL\Schema\Schema;
7use Symfony\Component\DependencyInjection\ContainerAwareInterface;
8use Symfony\Component\DependencyInjection\ContainerInterface;
9
10/**
11 * Add the restricted_access internal setting for articles with paywall
12 */
13class Version20161122144743 extends AbstractMigration implements ContainerAwareInterface
14{
15 /**
16 * @var ContainerInterface
17 */
18 private $container;
19
20 public function setContainer(ContainerInterface $container = null)
21 {
22 $this->container = $container;
23 }
24
25 private function getTable($tableName)
26 {
27 return $this->container->getParameter('database_table_prefix') . $tableName;
28 }
29
30 /**
31 * @param Schema $schema
32 */
33 public function up(Schema $schema)
34 {
35 $this->addSql("INSERT INTO ".$this->getTable('craue_config_setting')." (name, value, section) VALUES ('restricted_access', 0, 'entry')");
36 }
37
38 /**
39 * @param Schema $schema
40 */
41 public function down(Schema $schema)
42 {
43 $this->addSql("DELETE FROM ".$this->getTable('craue_config_setting')." WHERE name = 'restricted_access';");
44 }
45}
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml
index fac3b4f8..c65463db 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.da.yml
@@ -32,3 +32,4 @@ demo_mode_enabled: "Aktiver demo-indstilling? (anvendes kun til wallabags offent
32demo_mode_username: "Demobruger" 32demo_mode_username: "Demobruger"
33# share_public: Allow public url for entries 33# share_public: Allow public url for entries
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml
index d382733c..bc378147 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml
@@ -32,3 +32,4 @@ demo_mode_enabled: "Test-Modus aktivieren? (nur für die öffentliche wallabag-D
32demo_mode_username: "Test-Benutzer" 32demo_mode_username: "Test-Benutzer"
33share_public: Erlaube eine öffentliche URL für Einträge 33share_public: Erlaube eine öffentliche URL für Einträge
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml
index 23de7a43..52cb8e20 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.en.yml
@@ -32,3 +32,4 @@ demo_mode_enabled: "Enable demo mode ? (only used for the wallabag public demo)"
32demo_mode_username: "Demo user" 32demo_mode_username: "Demo user"
33share_public: Allow public url for entries 33share_public: Allow public url for entries
34download_images_enabled: Download images locally 34download_images_enabled: Download images locally
35restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml
index ff1dd04f..dbec0e81 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.es.yml
@@ -32,3 +32,4 @@ demo_mode_enabled: "Activar modo demo (sólo usado para la demo de wallabag)"
32demo_mode_username: "Nombre de usuario demo" 32demo_mode_username: "Nombre de usuario demo"
33# share_public: Allow public url for entries 33# share_public: Allow public url for entries
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml
index 4e712fdd..7a341e0b 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fa.yml
@@ -32,3 +32,4 @@ modify_settings: "اعمال"
32# demo_mode_username: "Demo user" 32# demo_mode_username: "Demo user"
33# share_public: Allow public url for entries 33# share_public: Allow public url for entries
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml
index cae4c662..f5c886d6 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.fr.yml
@@ -32,3 +32,4 @@ demo_mode_enabled: "Activer le mode démo ? (utiliser uniquement pour la démo p
32demo_mode_username: "Utilisateur de la démo" 32demo_mode_username: "Utilisateur de la démo"
33share_public: Autoriser une URL publique pour les articles 33share_public: Autoriser une URL publique pour les articles
34download_images_enabled: Télécharger les images en local 34download_images_enabled: Télécharger les images en local
35restricted_access: Activer l'authentification pour les articles derrière un paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml
index f94f834f..88a1b4f6 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.it.yml
@@ -32,3 +32,4 @@ demo_mode_enabled: "Abilita modalità demo ? (usato solo per la demo pubblica di
32demo_mode_username: "Utente Demo" 32demo_mode_username: "Utente Demo"
33# share_public: Allow public url for entries 33# share_public: Allow public url for entries
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml
index de60a194..00deeade 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.oc.yml
@@ -32,3 +32,4 @@ demo_mode_enabled: "Activar lo mode demostracion ? (utilizar solament per la dem
32demo_mode_username: "Utilizaire de la demostracion" 32demo_mode_username: "Utilizaire de la demostracion"
33# share_public: Allow public url for entries 33# share_public: Allow public url for entries
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml
index 11579745..744031e8 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pl.yml
@@ -32,3 +32,4 @@ demo_mode_enabled: "Włacz tryb demo? (używany wyłącznie dla publicznej demon
32demo_mode_username: "Użytkownik Demonstracyjny" 32demo_mode_username: "Użytkownik Demonstracyjny"
33share_public: Zezwalaj na publiczny adres url dla wpisow 33share_public: Zezwalaj na publiczny adres url dla wpisow
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pt.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pt.yml
index 74ae5a44..1edde87a 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pt.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.pt.yml
@@ -32,3 +32,4 @@ demo_mode_enabled: "Habilitar modo demo? (somente usado para o demo público do
32demo_mode_username: "Usuário demo" 32demo_mode_username: "Usuário demo"
33# share_public: Allow public url for entries 33# share_public: Allow public url for entries
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml
index 5095dfa0..f0c935d3 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.ro.yml
@@ -32,3 +32,4 @@ modify_settings: "aplică"
32# demo_mode_username: "Demo user" 32# demo_mode_username: "Demo user"
33# share_public: Allow public url for entries 33# share_public: Allow public url for entries
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.tr.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.tr.yml
index cd42e595..eb40fc5e 100644
--- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.tr.yml
+++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.tr.yml
@@ -32,3 +32,4 @@
32# demo_mode_username: "Demo user" 32# demo_mode_username: "Demo user"
33# share_public: Allow public url for entries 33# share_public: Allow public url for entries
34# download_images_enabled: Download images locally 34# download_images_enabled: Download images locally
35# restricted_access: Enable authentication for websites with paywall
diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist
index f821f2a8..a4dc0bde 100644
--- a/app/config/parameters.yml.dist
+++ b/app/config/parameters.yml.dist
@@ -56,3 +56,6 @@ parameters:
56 redis_port: 6379 56 redis_port: 6379
57 redis_path: null 57 redis_path: null
58 redis_password: null 58 redis_password: null
59
60 # sites credentials
61 sites_credentials: {}
diff --git a/composer.json b/composer.json
index 1548d6ec..e2aeb424 100644
--- a/composer.json
+++ b/composer.json
@@ -83,7 +83,8 @@
83 "predis/predis": "^1.0", 83 "predis/predis": "^1.0",
84 "javibravo/simpleue": "^1.0", 84 "javibravo/simpleue": "^1.0",
85 "symfony/dom-crawler": "^3.1", 85 "symfony/dom-crawler": "^3.1",
86 "friendsofsymfony/jsrouting-bundle": "^1.6" 86 "friendsofsymfony/jsrouting-bundle": "^1.6",
87 "bdunogier/guzzle-site-authenticator": "^1.0@beta"
87 }, 88 },
88 "require-dev": { 89 "require-dev": {
89 "doctrine/doctrine-fixtures-bundle": "~2.2", 90 "doctrine/doctrine-fixtures-bundle": "~2.2",
diff --git a/docs/de/developer/paywall.rst b/docs/de/developer/paywall.rst
new file mode 100644
index 00000000..365027b4
--- /dev/null
+++ b/docs/de/developer/paywall.rst
@@ -0,0 +1,56 @@
1Articles behind a paywall
2=========================
3
4wallabag can fetch articles from websites which use a paywall system.
5
6Enable paywall authentication
7-----------------------------
8
9In internal settings, in the **Article** section, enable authentication for websites with paywall (with the value 1).
10
11Configure credentials in wallabag
12---------------------------------
13
14Edit your ``app/config/parameters.yml`` file to edit credentials for each website with paywall. Here is an example for some french websites:
15
16.. code:: yaml
17
18 sites_credentials:
19 mediapart.fr: {username: "myMediapartLogin", password: "mypassword"}
20 arretsurimages.net: {username: "myASILogin", password: "mypassword"}
21
22.. note::
23
24 These credentials will be shared between each user of your wallabag instance.
25
26Parsing configuration files
27---------------------------
28
29.. note::
30
31 Read `this part of the documentation <http://doc.wallabag.org/en/master/user/errors_during_fetching.html>`_ to understand the configuration files.
32
33Each parsing configuration file needs to be improved by adding ``requires_login``, ``login_uri``,
34``login_username_field``, ``login_password_field`` and ``not_logged_in_xpath``.
35
36Be careful, the login form must be in the page content when wallabag loads it. It's impossible for wallabag to be authenticated
37on a website where the login form is loaded after the page (by ajax for example).
38
39``login_uri`` is the action URL of the form (``action`` attribute in the form).
40``login_username_field`` is the ``name`` attribute of the login field.
41``login_password_field`` is the ``name`` attribute of the password field.
42
43For example:
44
45.. code::
46
47 title://div[@id="titrage-contenu"]/h1[@class="title"]
48 body: //div[@class="contenu-html"]/div[@class="page-pane"]
49
50 requires_login: yes
51
52 login_uri: http://www.arretsurimages.net/forum/login.php
53 login_username_field: username
54 login_password_field: password
55
56 not_logged_in_xpath: //body[@class="not-logged-in"]
diff --git a/docs/de/index.rst b/docs/de/index.rst
index c1ce7d4b..1c3e4873 100644
--- a/docs/de/index.rst
+++ b/docs/de/index.rst
@@ -46,6 +46,7 @@ Die Dokumentation ist in anderen Sprachen verfügbar :
46 46
47 developer/api 47 developer/api
48 developer/docker 48 developer/docker
49 developer/paywall
49 developer/documentation 50 developer/documentation
50 developer/translate 51 developer/translate
51 developer/asynchronous 52 developer/asynchronous
diff --git a/docs/en/developer/paywall.rst b/docs/en/developer/paywall.rst
new file mode 100644
index 00000000..365027b4
--- /dev/null
+++ b/docs/en/developer/paywall.rst
@@ -0,0 +1,56 @@
1Articles behind a paywall
2=========================
3
4wallabag can fetch articles from websites which use a paywall system.
5
6Enable paywall authentication
7-----------------------------
8
9In internal settings, in the **Article** section, enable authentication for websites with paywall (with the value 1).
10
11Configure credentials in wallabag
12---------------------------------
13
14Edit your ``app/config/parameters.yml`` file to edit credentials for each website with paywall. Here is an example for some french websites:
15
16.. code:: yaml
17
18 sites_credentials:
19 mediapart.fr: {username: "myMediapartLogin", password: "mypassword"}
20 arretsurimages.net: {username: "myASILogin", password: "mypassword"}
21
22.. note::
23
24 These credentials will be shared between each user of your wallabag instance.
25
26Parsing configuration files
27---------------------------
28
29.. note::
30
31 Read `this part of the documentation <http://doc.wallabag.org/en/master/user/errors_during_fetching.html>`_ to understand the configuration files.
32
33Each parsing configuration file needs to be improved by adding ``requires_login``, ``login_uri``,
34``login_username_field``, ``login_password_field`` and ``not_logged_in_xpath``.
35
36Be careful, the login form must be in the page content when wallabag loads it. It's impossible for wallabag to be authenticated
37on a website where the login form is loaded after the page (by ajax for example).
38
39``login_uri`` is the action URL of the form (``action`` attribute in the form).
40``login_username_field`` is the ``name`` attribute of the login field.
41``login_password_field`` is the ``name`` attribute of the password field.
42
43For example:
44
45.. code::
46
47 title://div[@id="titrage-contenu"]/h1[@class="title"]
48 body: //div[@class="contenu-html"]/div[@class="page-pane"]
49
50 requires_login: yes
51
52 login_uri: http://www.arretsurimages.net/forum/login.php
53 login_username_field: username
54 login_password_field: password
55
56 not_logged_in_xpath: //body[@class="not-logged-in"]
diff --git a/docs/en/index.rst b/docs/en/index.rst
index 54a1eef8..2e20aee6 100644
--- a/docs/en/index.rst
+++ b/docs/en/index.rst
@@ -46,6 +46,7 @@ The documentation is available in other languages:
46 46
47 developer/api 47 developer/api
48 developer/docker 48 developer/docker
49 developer/paywall
49 developer/documentation 50 developer/documentation
50 developer/translate 51 developer/translate
51 developer/asynchronous 52 developer/asynchronous
diff --git a/docs/fr/developer/paywall.rst b/docs/fr/developer/paywall.rst
new file mode 100644
index 00000000..c1c410b1
--- /dev/null
+++ b/docs/fr/developer/paywall.rst
@@ -0,0 +1,56 @@
1Articles derrière un paywall
2============================
3
4wallabag peut récupérer le contenu des articles des sites qui utilisent un système de paiement.
5
6Activer l'authentification pour les paywall
7-------------------------------------------
8
9Dans les paramètres internes, section **Article**, activez l'authentification pour les articles derrière un paywall (avec la valeur 1).
10
11Configurer les accès dans wallabag
12----------------------------------
13
14Éditez le fichier ``app/config/parameters.yml`` pour modifier les accès aux sites avec paywall. Voici un exemple pour certains sites :
15
16.. code:: yaml
17
18 sites_credentials:
19 mediapart.fr: {username: "myMediapartLogin", password: "mypassword"}
20 arretsurimages.net: {username: "myASILogin", password: "mypassword"}
21
22.. note::
23
24 Ces accès seront partagés entre chaque utilisateur de votre instance wallabag.
25
26Fichiers de configuration pour parser les articles
27--------------------------------------------------
28
29.. note::
30
31 Lisez `cette documentation <http://doc.wallabag.org/fr/master/user/errors_during_fetching.html>`_ pour en savoir plus sur ces fichiers de configuration.
32
33Chaque fichier de configuration doit être enrichi en ajoutant ``requires_login``, ``login_uri``,
34``login_username_field``, ``login_password_field`` et ``not_logged_in_xpath``.
35
36Attention, le formulaire de connexion doit se trouver dans le contenu de la page lors du chargement de celle-ci.
37Il sera impossible pour wallabag de se connecter à un site dont le formulaire de connexion est chargé après coup (en ajax par exemple).
38
39``login_uri`` correspond à l'URL à laquelle le formulaire est soumis (attribut ``action`` du formulaire).
40``login_username_field`` correspond à l'attribut ``name`` du champ de l'identifiant.
41``login_password_field`` correspond à l'attribut ``name`` du champ du mot de passe.
42
43Par exemple :
44
45.. code::
46
47 title://div[@id="titrage-contenu"]/h1[@class="title"]
48 body: //div[@class="contenu-html"]/div[@class="page-pane"]
49
50 requires_login: yes
51
52 login_uri: http://www.arretsurimages.net/forum/login.php
53 login_username_field: username
54 login_password_field: password
55
56 not_logged_in_xpath: //body[@class="not-logged-in"]
diff --git a/docs/fr/index.rst b/docs/fr/index.rst
index 8a4c600a..e3f14b04 100644
--- a/docs/fr/index.rst
+++ b/docs/fr/index.rst
@@ -47,6 +47,7 @@ La documentation est disponible dans d'autres langues :
47 47
48 developer/api 48 developer/api
49 developer/docker 49 developer/docker
50 developer/paywall
50 developer/documentation 51 developer/documentation
51 developer/translate 52 developer/translate
52 developer/asynchronous 53 developer/asynchronous
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php
index e95c3a7b..f0738b91 100644
--- a/src/Wallabag/CoreBundle/Command/InstallCommand.php
+++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php
@@ -432,6 +432,11 @@ class InstallCommand extends ContainerAwareCommand
432 'value' => '0', 432 'value' => '0',
433 'section' => 'misc', 433 'section' => 'misc',
434 ], 434 ],
435 [
436 'name' => 'restricted_access',
437 'value' => '0',
438 'section' => 'entry',
439 ],
435 ]; 440 ];
436 441
437 foreach ($settings as $setting) { 442 foreach ($settings as $setting) {
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
index 1f74891a..a723656e 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
@@ -155,6 +155,11 @@ class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface
155 'value' => '0', 155 'value' => '0',
156 'section' => 'misc', 156 'section' => 'misc',
157 ], 157 ],
158 [
159 'name' => 'restricted_access',
160 'value' => '0',
161 'section' => 'entry',
162 ],
158 ]; 163 ];
159 164
160 foreach ($settings as $setting) { 165 foreach ($settings as $setting) {
diff --git a/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php
new file mode 100644
index 00000000..6d4129e8
--- /dev/null
+++ b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php
@@ -0,0 +1,68 @@
1<?php
2
3namespace Wallabag\CoreBundle\GuzzleSiteAuthenticator;
4
5use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfig;
6use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfigBuilder;
7use Graby\SiteConfig\ConfigBuilder;
8use OutOfRangeException;
9
10class GrabySiteConfigBuilder implements SiteConfigBuilder
11{
12 /**
13 * @var \Graby\SiteConfig\ConfigBuilder
14 */
15 private $grabyConfigBuilder;
16 /**
17 * @var array
18 */
19 private $credentials;
20
21 /**
22 * GrabySiteConfigBuilder constructor.
23 *
24 * @param \Graby\SiteConfig\ConfigBuilder $grabyConfigBuilder
25 * @param array $credentials
26 */
27 public function __construct(ConfigBuilder $grabyConfigBuilder, array $credentials = [])
28 {
29 $this->grabyConfigBuilder = $grabyConfigBuilder;
30 $this->credentials = $credentials;
31 }
32
33 /**
34 * Builds the SiteConfig for a host.
35 *
36 * @param string $host The "www." prefix is ignored
37 *
38 * @return SiteConfig
39 *
40 * @throws OutOfRangeException If there is no config for $host
41 */
42 public function buildForHost($host)
43 {
44 // required by credentials below
45 $host = strtolower($host);
46 if (substr($host, 0, 4) == 'www.') {
47 $host = substr($host, 4);
48 }
49
50 $config = $this->grabyConfigBuilder->buildForHost($host);
51 $parameters = [
52 'host' => $host,
53 'requiresLogin' => $config->requires_login ?: false,
54 'loginUri' => $config->login_uri ?: null,
55 'usernameField' => $config->login_username_field ?: null,
56 'passwordField' => $config->login_password_field ?: null,
57 'extraFields' => is_array($config->login_extra_fields) ? $config->login_extra_fields : [],
58 'notLoggedInXpath' => $config->not_logged_in_xpath ?: null,
59 ];
60
61 if (isset($this->credentials[$host])) {
62 $parameters['username'] = $this->credentials[$host]['username'];
63 $parameters['password'] = $this->credentials[$host]['password'];
64 }
65
66 return new SiteConfig($parameters);
67 }
68}
diff --git a/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php b/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php
new file mode 100644
index 00000000..8891887b
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php
@@ -0,0 +1,54 @@
1<?php
2
3namespace Wallabag\CoreBundle\Helper;
4
5use Graby\Ring\Client\SafeCurlHandler;
6use GuzzleHttp\Client;
7use GuzzleHttp\Cookie\CookieJar;
8use GuzzleHttp\Event\SubscriberInterface;
9
10/**
11 * Builds and configures the Guzzle HTTP client.
12 */
13class HttpClientFactory
14{
15 /** @var \GuzzleHttp\Event\SubscriberInterface */
16 private $authenticatorSubscriber;
17
18 /** @var \GuzzleHttp\Cookie\CookieJar */
19 private $cookieJar;
20
21 private $restrictedAccess;
22
23 /**
24 * HttpClientFactory constructor.
25 *
26 * @param \GuzzleHttp\Event\SubscriberInterface $authenticatorSubscriber
27 * @param \GuzzleHttp\Cookie\CookieJar $cookieJar
28 * @param string $restrictedAccess this param is a kind of boolean. Values: 0 or 1
29 */
30 public function __construct(SubscriberInterface $authenticatorSubscriber, CookieJar $cookieJar, $restrictedAccess)
31 {
32 $this->authenticatorSubscriber = $authenticatorSubscriber;
33 $this->cookieJar = $cookieJar;
34 $this->restrictedAccess = $restrictedAccess;
35 }
36
37 /**
38 * @return \GuzzleHttp\Client|null
39 */
40 public function buildHttpClient()
41 {
42 if (0 === (int) $this->restrictedAccess) {
43 return null;
44 }
45
46 // we clear the cookie to avoid websites who use cookies for analytics
47 $this->cookieJar->clear();
48 // need to set the (shared) cookie jar
49 $client = new Client(['handler' => new SafeCurlHandler(), 'defaults' => ['cookies' => $this->cookieJar]]);
50 $client->getEmitter()->attach($this->authenticatorSubscriber);
51
52 return $client;
53 }
54}
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml
index 0280bc18..bcf0c9ca 100644
--- a/src/Wallabag/CoreBundle/Resources/config/services.yml
+++ b/src/Wallabag/CoreBundle/Resources/config/services.yml
@@ -41,11 +41,44 @@ services:
41 arguments: 41 arguments:
42 - 42 -
43 error_message: '%wallabag_core.fetching_error_message%' 43 error_message: '%wallabag_core.fetching_error_message%'
44 - "@wallabag_core.guzzle.http_client"
45 - "@wallabag_core.graby.config_builder"
44 calls: 46 calls:
45 - [ setLogger, [ "@logger" ] ] 47 - [ setLogger, [ "@logger" ] ]
46 tags: 48 tags:
47 - { name: monolog.logger, channel: graby } 49 - { name: monolog.logger, channel: graby }
48 50
51 wallabag_core.graby.config_builder:
52 class: Graby\SiteConfig\ConfigBuilder
53 arguments:
54 - {}
55 - "@logger"
56
57 wallabag_core.guzzle.http_client:
58 class: GuzzleHttp\ClientInterface
59 factory: ["@wallabag_core.guzzle.http_client_factory", buildHttpClient]
60
61 wallabag_core.guzzle_authenticator.config_builder:
62 class: Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder
63 arguments:
64 - "@wallabag_core.graby.config_builder"
65 - "%sites_credentials%"
66
67 # service alias override
68 bd_guzzle_site_authenticator.site_config_builder:
69 alias: wallabag_core.guzzle_authenticator.config_builder
70
71 wallabag_core.guzzle.http_client_factory:
72 class: Wallabag\CoreBundle\Helper\HttpClientFactory
73 arguments:
74 - "@bd_guzzle_site_authenticator.authenticator_subscriber"
75 - "@wallabag_core.guzzle.cookie_jar"
76 - '@=service(''craue_config'').get(''restricted_access'')'
77
78 wallabag_core.guzzle.cookie_jar:
79 class: GuzzleHttp\Cookie\FileCookieJar
80 arguments: ["%kernel.cache_dir%/cookiejar.json"]
81
49 wallabag_core.content_proxy: 82 wallabag_core.content_proxy:
50 class: Wallabag\CoreBundle\Helper\ContentProxy 83 class: Wallabag\CoreBundle\Helper\ContentProxy
51 arguments: 84 arguments:
diff --git a/tests/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilderTest.php b/tests/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilderTest.php
new file mode 100644
index 00000000..aee67259
--- /dev/null
+++ b/tests/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilderTest.php
@@ -0,0 +1,85 @@
1<?php
2
3namespace Tests\Wallabag\CoreBundle\GuzzleSiteAuthenticator;
4
5use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfig;
6use Graby\SiteConfig\SiteConfig as GrabySiteConfig;
7use PHPUnit_Framework_TestCase;
8use Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder;
9
10class GrabySiteConfigBuilderTest extends PHPUnit_Framework_TestCase
11{
12 /** @var \Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder */
13 protected $builder;
14
15 public function testBuildConfigExists()
16 {
17 /* @var \Graby\SiteConfig\ConfigBuilder|\PHPUnit_Framework_MockObject_MockObject */
18 $grabyConfigBuilderMock = $this->getMockBuilder('\Graby\SiteConfig\ConfigBuilder')
19 ->disableOriginalConstructor()
20 ->getMock();
21
22 $grabySiteConfig = new GrabySiteConfig();
23 $grabySiteConfig->requires_login = true;
24 $grabySiteConfig->login_uri = 'http://example.com/login';
25 $grabySiteConfig->login_username_field = 'login';
26 $grabySiteConfig->login_password_field = 'password';
27 $grabySiteConfig->login_extra_fields = ['field' => 'value'];
28 $grabySiteConfig->not_logged_in_xpath = '//div[@class="need-login"]';
29
30 $grabyConfigBuilderMock
31 ->method('buildForHost')
32 ->with('example.com')
33 ->will($this->returnValue($grabySiteConfig));
34
35 $this->builder = new GrabySiteConfigBuilder(
36 $grabyConfigBuilderMock,
37 ['example.com' => ['username' => 'foo', 'password' => 'bar']]
38 );
39
40 $config = $this->builder->buildForHost('example.com');
41
42 self::assertEquals(
43 new SiteConfig([
44 'host' => 'example.com',
45 'requiresLogin' => true,
46 'loginUri' => 'http://example.com/login',
47 'usernameField' => 'login',
48 'passwordField' => 'password',
49 'extraFields' => ['field' => 'value'],
50 'notLoggedInXpath' => '//div[@class="need-login"]',
51 'username' => 'foo',
52 'password' => 'bar',
53 ]),
54 $config
55 );
56 }
57
58 public function testBuildConfigDoesntExist()
59 {
60 /* @var \Graby\SiteConfig\ConfigBuilder|\PHPUnit_Framework_MockObject_MockObject */
61 $grabyConfigBuilderMock = $this->getMockBuilder('\Graby\SiteConfig\ConfigBuilder')
62 ->disableOriginalConstructor()
63 ->getMock();
64
65 $grabyConfigBuilderMock
66 ->method('buildForHost')
67 ->with('unknown.com')
68 ->will($this->returnValue(new GrabySiteConfig()));
69
70 $this->builder = new GrabySiteConfigBuilder($grabyConfigBuilderMock, []);
71
72 $config = $this->builder->buildForHost('unknown.com');
73
74 self::assertEquals(
75 new SiteConfig([
76 'host' => 'unknown.com',
77 'requiresLogin' => false,
78 'username' => null,
79 'password' => null,
80 'extraFields' => [],
81 ]),
82 $config
83 );
84 }
85}