]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #3944 from shtrom/always-hash-exists-url 3984/head
authorJérémy Benoist <j0k3r@users.noreply.github.com>
Tue, 28 May 2019 12:18:33 +0000 (14:18 +0200)
committerGitHub <noreply@github.com>
Tue, 28 May 2019 12:18:33 +0000 (14:18 +0200)
Always hash exists url

src/Wallabag/ApiBundle/Controller/EntryRestController.php
src/Wallabag/CoreBundle/Command/GenerateUrlHashesCommand.php
src/Wallabag/CoreBundle/Entity/Entry.php
src/Wallabag/CoreBundle/Helper/UrlHasher.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Repository/EntryRepository.php

index d9d99c85b0f55c6066cdb236734e37439035cb34..aaacdcdc9206cf9baeddbad79059eb7c9f78a99a 100644 (file)
@@ -14,6 +14,7 @@ use Wallabag\CoreBundle\Entity\Entry;
 use Wallabag\CoreBundle\Entity\Tag;
 use Wallabag\CoreBundle\Event\EntryDeletedEvent;
 use Wallabag\CoreBundle\Event\EntrySavedEvent;
+use Wallabag\CoreBundle\Helper\UrlHasher;
 
 class EntryRestController extends WallabagRestController
 {
@@ -43,50 +44,45 @@ class EntryRestController extends WallabagRestController
 
         $returnId = (null === $request->query->get('return_id')) ? false : (bool) $request->query->get('return_id');
 
-        $urls = $request->query->get('urls', []);
         $hashedUrls = $request->query->get('hashed_urls', []);
+        $hashedUrl = $request->query->get('hashed_url', '');
+        if (!empty($hashedUrl)) {
+            $hashedUrls[] = $hashedUrl;
+        }
 
-        // handle multiple urls first
-        if (!empty($hashedUrls)) {
-            $results = [];
-            foreach ($hashedUrls as $hashedUrl) {
-                $res = $repo->findByHashedUrlAndUserId($hashedUrl, $this->getUser()->getId());
-
-                $results[$hashedUrl] = $this->returnExistInformation($res, $returnId);
-            }
+        $urls = $request->query->get('urls', []);
+        $url = $request->query->get('url', '');
+        if (!empty($url)) {
+            $urls[] = $url;
+        }
 
-            return $this->sendResponse($results);
+        $urlHashMap = [];
+        foreach ($urls as $urlToHash) {
+            $urlHash = UrlHasher::hashUrl($urlToHash);
+            $hashedUrls[] = $urlHash;
+            $urlHashMap[$urlHash] = $urlToHash;
         }
 
-        // @deprecated, to be remove in 3.0
-        if (!empty($urls)) {
-            $results = [];
-            foreach ($urls as $url) {
-                $res = $repo->findByUrlAndUserId($url, $this->getUser()->getId());
+        if (empty($hashedUrls)) {
+            throw $this->createAccessDeniedException('URL is empty?, logged user id: ' . $this->getUser()->getId());
+        }
 
-                $results[$url] = $this->returnExistInformation($res, $returnId);
-            }
+        $results = [];
+        foreach ($hashedUrls as $hashedUrlToSearch) {
+            $res = $repo->findByHashedUrlAndUserId($hashedUrlToSearch, $this->getUser()->getId());
 
-            return $this->sendResponse($results);
+            $results[$hashedUrlToSearch] = $this->returnExistInformation($res, $returnId);
         }
 
-        // let's see if it is a simple url?
-        $url = $request->query->get('url', '');
-        $hashedUrl = $request->query->get('hashed_url', '');
+        $results = $this->replaceUrlHashes($results, $urlHashMap);
 
-        if (empty($url) && empty($hashedUrl)) {
-            throw $this->createAccessDeniedException('URL is empty?, logged user id: ' . $this->getUser()->getId());
-        }
+        if (!empty($url) || !empty($hashedUrl)) {
+            $hu = array_keys($results)[0];
 
-        $method = 'findByUrlAndUserId';
-        if (!empty($hashedUrl)) {
-            $method = 'findByHashedUrlAndUserId';
-            $url = $hashedUrl;
+            return $this->sendResponse(['exists' => $results[$hu]]);
         }
 
-        $res = $repo->$method($url, $this->getUser()->getId());
-
-        return $this->sendResponse(['exists' => $this->returnExistInformation($res, $returnId)]);
+        return $this->sendResponse($results);
     }
 
     /**
@@ -804,6 +800,24 @@ class EntryRestController extends WallabagRestController
         return $this->sendResponse($results);
     }
 
+    /**
+     * Replace the hashedUrl keys in $results with the unhashed URL from the
+     * request, as recorded in $urlHashMap.
+     */
+    private function replaceUrlHashes(array $results, array $urlHashMap)
+    {
+        $newResults = [];
+        foreach ($results as $hash => $res) {
+            if (isset($urlHashMap[$hash])) {
+                $newResults[$urlHashMap[$hash]] = $res;
+            } else {
+                $newResults[$hash] = $res;
+            }
+        }
+
+        return $newResults;
+    }
+
     /**
      * Retrieve value from the request.
      * Used for POST & PATCH on a an entry.
@@ -832,8 +846,8 @@ class EntryRestController extends WallabagRestController
     /**
      * Return information about the entry if it exist and depending on the id or not.
      *
-     * @param Entry|null $entry
-     * @param bool       $returnId
+     * @param Entry|bool|null $entry
+     * @param bool            $returnId
      *
      * @return bool|int
      */
index 45bd8c5ffd08a505120db9c2e28ff4e3fe6316dd..8f2bff114096d4a6ba24578d96d38636bb1f1fb2 100644 (file)
@@ -7,6 +7,7 @@ use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
 use Symfony\Component\Console\Input\InputArgument;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
+use Wallabag\CoreBundle\Helper\UrlHasher;
 use Wallabag\UserBundle\Entity\User;
 
 class GenerateUrlHashesCommand extends ContainerAwareCommand
@@ -65,7 +66,7 @@ class GenerateUrlHashesCommand extends ContainerAwareCommand
 
         $i = 1;
         foreach ($entries as $entry) {
-            $entry->setHashedUrl(hash('sha1', $entry->getUrl()));
+            $entry->setHashedUrl(UrlHasher::hashUrl($entry->getUrl()));
             $em->persist($entry);
 
             if (0 === ($i % 20)) {
@@ -84,7 +85,7 @@ class GenerateUrlHashesCommand extends ContainerAwareCommand
      *
      * @param string $username
      *
-     * @return \Wallabag\UserBundle\Entity\User
+     * @return User
      */
     private function getUser($username)
     {
index c3fb87d218630875e77047002fad2bad55b091d1..1b4367fd79d6feee50a98a43758f4bd0d2500a9d 100644 (file)
@@ -13,6 +13,7 @@ use JMS\Serializer\Annotation\XmlRoot;
 use Symfony\Component\Validator\Constraints as Assert;
 use Wallabag\AnnotationBundle\Entity\Annotation;
 use Wallabag\CoreBundle\Helper\EntityTimestampsTrait;
+use Wallabag\CoreBundle\Helper\UrlHasher;
 use Wallabag\UserBundle\Entity\User;
 
 /**
@@ -324,7 +325,7 @@ class Entry
     public function setUrl($url)
     {
         $this->url = $url;
-        $this->hashedUrl = hash('sha1', $url);
+        $this->hashedUrl = UrlHasher::hashUrl($url);
 
         return $this;
     }
diff --git a/src/Wallabag/CoreBundle/Helper/UrlHasher.php b/src/Wallabag/CoreBundle/Helper/UrlHasher.php
new file mode 100644 (file)
index 0000000..d123eab
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+
+namespace Wallabag\CoreBundle\Helper;
+
+/**
+ * Hash URLs for privacy and performance.
+ */
+class UrlHasher
+{
+    /**
+     * Hash the given url using the given algorithm.
+     * Hashed url are faster to be retrieved in the database than the real url.
+     *
+     * @param string $url
+     * @param string $algorithm
+     *
+     * @return string
+     */
+    public static function hashUrl(string $url, $algorithm = 'sha1')
+    {
+        return hash($algorithm, urldecode($url));
+    }
+}
index 3990932e14a1261dcf49b3b9283fc5ede0182caf..880e7c65aa0a0e0b8aa2007171f76feadae219c3 100644 (file)
@@ -9,6 +9,7 @@ use Pagerfanta\Adapter\DoctrineORMAdapter;
 use Pagerfanta\Pagerfanta;
 use Wallabag\CoreBundle\Entity\Entry;
 use Wallabag\CoreBundle\Entity\Tag;
+use Wallabag\CoreBundle\Helper\UrlHasher;
 
 class EntryRepository extends EntityRepository
 {
@@ -348,17 +349,10 @@ class EntryRepository extends EntityRepository
      */
     public function findByUrlAndUserId($url, $userId)
     {
-        $res = $this->createQueryBuilder('e')
-            ->where('e.url = :url')->setParameter('url', urldecode($url))
-            ->andWhere('e.user = :user_id')->setParameter('user_id', $userId)
-            ->getQuery()
-            ->getResult();
-
-        if (\count($res)) {
-            return current($res);
-        }
-
-        return false;
+        return $this->findByHashedUrlAndUserId(
+            UrlHasher::hashUrl($url),
+            $userId
+        );
     }
 
     /**