Behavior on published content.

Created on 4 April 2022, over 2 years ago
Updated 16 July 2024, 5 months ago

Problem/Motivation

Currently, the preview link module will serve content through the preview link URL as normal if it is published, and/or the user would normally be able to access it. What's more, the preview URL doesn't even need to be valid, e.g. http://localhost:8080/preview-link/node/1/blah will work just fine.

This gives the appearance that preview link URLs are not successfully expiring. Even if they can access the content through the normal URL. This can lead to some situations where users will propagate a previously shared preview link, that appears to work fine (they may not even be aware that it is a preview URL).

I just had a client say some stranger sent them one of their own preview URLs, and we aren't sure how they got a hold of it.

Steps to reproduce

  1. Create a node with preview link enabled.
  2. Copy the preview link URL.
  3. Publish the node
  4. Visit the Preview link URL as an anonymous user

You can see the content in the preview link.

Also, delete the contents of the preview_link table, and visit the page with a preview link prefix URL. e.g. http://localhost:8080/preview-link/node/1/blah. You will see the content just fine.

Proposed resolution

I'm not sure what to propose, perhaps permanent redirect?

✨ Feature request
Status

Active

Version

2.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States bburg Washington D.C.

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡ΊπŸ‡ΈUnited States phillamb168

    I needed this functionality as well. I modified the functionality on PreviewLinkController::preview() so that it:
    1. checks entity->status->value to see if it's published
    2. if published, calls the sessiontokencontroller and removes the tokens (to avoid redirect loops)
    3. redirects to the new entity URL.

    I'm pasting in the patch file while I figure out how to submit a patch - it's been a while so I need to remember how to do it.

    diff --git a/preview_link.services.yml b/preview_link.services.yml
    index 5f11fab..af709ef 100644
    --- a/preview_link.services.yml
    +++ b/preview_link.services.yml
    @@ -51,6 +51,22 @@ services:
         arguments: ['@entity_type.manager']
         tags:
           - { name: event_subscriber }
    +  preview_link.session_token_controller:
    +    class: Drupal\preview_link\Controller\PreviewLinkSessionTokenController
    +    arguments:
    +      - '@string_translation'
    +      - '@messenger'
    +      - '@tempstore.private'
    +  preview_link.controller:
    +    class: Drupal\preview_link\Controller\PreviewLinkController
    +    arguments:
    +      - '@entity_type.manager'
    +      - '@tempstore.private'
    +      - '@config.factory'
    +      - '@preview_link.message'
    +      - '@messenger'
    +      - '@preview_link.hook_helper'
    +      - '@preview_link.session_token_controller'
       logger.channel.preview_link:
         parent: logger.channel_base
         arguments: [ 'preview_link' ]
    diff --git a/src/Controller/PreviewLinkController.php b/src/Controller/PreviewLinkController.php
    index d4cf5f3..8acd37c 100644
    --- a/src/Controller/PreviewLinkController.php
    +++ b/src/Controller/PreviewLinkController.php
    @@ -15,11 +15,15 @@ use Drupal\Core\TempStore\PrivateTempStoreFactory;
     use Drupal\preview_link\PreviewLinkHookHelper;
     use Drupal\preview_link\PreviewLinkMessageInterface;
     use Symfony\Component\DependencyInjection\ContainerInterface;
    +use Symfony\Component\HttpFoundation\RedirectResponse;
    +use Drupal\preview_link\Controller\PreviewLinkSessionTokenController;
    +
     
     /**
      * Preview link controller to view any entity.
      */
     class PreviewLinkController extends ControllerBase {
    +  protected PreviewLinkSessionTokenController $sessionTokenController;
     
       /**
        * PreviewLinkController constructor.
    @@ -44,10 +48,12 @@ class PreviewLinkController extends ControllerBase {
         protected PreviewLinkMessageInterface $previewLinkMessages,
         MessengerInterface $messenger,
         protected PreviewLinkHookHelper $hookHelper,
    +    PreviewLinkSessionTokenController $sessionTokenController
       ) {
         $this->entityTypeManager = $entityTypeManager;
         $this->configFactory = $configFactory;
         $this->messenger = $messenger;
    +    $this->sessionTokenController = $sessionTokenController;
       }
     
       /**
    @@ -60,7 +66,8 @@ class PreviewLinkController extends ControllerBase {
           $container->get('config.factory'),
           $container->get('preview_link.message'),
           $container->get('messenger'),
    -      $container->get('preview_link.hook_helper')
    +      $container->get('preview_link.hook_helper'),
    +      $container->get('preview_link.session_token_controller')
         );
       }
     
    @@ -75,12 +82,18 @@ class PreviewLinkController extends ControllerBase {
        * @return array
        *   A render array for previewing the entity.
        */
    -  public function preview(RouteMatchInterface $routeMatch, string $preview_token): array {
    +  public function preview(RouteMatchInterface $routeMatch, string $preview_token): array|RedirectResponse {
         // Accessing the controller will bind the Preview Link token to the session.
         $this->claimToken($preview_token);
     
         $entity = $this->resolveEntity($routeMatch);
    -
    +    // Is the entity published?
    +    $is_published = $entity->status->value;
    +    if ($is_published && $routeMatch->getRouteName() !== $entity->getEntityType()->getLinkTemplate('canonical')) {
    +      // Redirect to the published node.
    +      $this->sessionTokenController->removeTokens();
    +      return new RedirectResponse($entity->toUrl()->toString());
    +    }
         $config = $this->configFactory->get('preview_link.settings');
         if (in_array($config->get('display_message'), ['always'], TRUE)) {
           // Reset static cache so our hook_entity_access is always re-evaluated.
    
Production build 0.71.5 2024