How to block access to files

Hi,

I need to block access to all content for unregistered users. I implemented “Restricting access to your site” cookbook and tried “Protecting files behind a firewall” cookbook and the plugin works, custom File::url component changes the urls but the media files are still generated, and the /content url to the file is redirected to the /media url.

My first time dealing with routes and plugins so any help would be much appreciated.

Could you post your route and file component here? Note that you also need to handle thumbs in a custom File::version component, as explained in the recipe. Have you set this up as well?

File::version works as well, no thumbs are generated.

Here are my plugin and config file:

sites/plugins/files-firewall/index.php

<?php

use Kirby\Cms\Response;

Kirby::plugin('cookbook/files-firewall', [
  'components'   => [
    'file::url' => function ($kirby, $file) {
      return $kirby->url() . '/' . $file->parent()->id() . '/' . $file->filename();
    },
    'file::version' => function ($kirby, $file, array $options = []) {
      static $original;
      return $file;

      if ($original === null) {
        $original = $kirby->nativeComponent('file::version');
      }

      return $original($kirby, $file, $options);
    }
  ],
]);

site/config/config.php

<?php
return [
  'panel' => true,
  'debug' => true,
  'cache' => [
    'pages' => [
      'active' => false
    ]
  ],
  'routes' => [
    [
      'pattern' => '(:all)',
      'action' => function () {

        if (!kirby()->user()) {
          return page('login');
        }

        $this->next();
      }
    ],
    [
      'pattern' => 'logout',
      'action'  => function () {

        if ($user = kirby()->user()) {
          $user->logout();
        }

        go('login');
      }
    ]
  ]
];

The problem here is that you want to apply the protected files to all pages, not a specific page like in the recipe. Therefore, you need something in your file route, that let’s you differentiate between a page and a file. The easiest way to achieve this, is to use a string between the page id and the filename in the file url:

Kirby::plugin('cookbook/files-firewall', [
  'components'   => [
    'file::url' => function ($kirby, $file) {
      return $kirby->url() . '/' . $file->parent()->id() . '/protected/' . $file->filename();
    },
    'file::version' => function ($kirby, $file, array $options = []) {
        return $file;
    },
  ]
]);

protected is just an example, you can change this to something else.

Then we can change our routes like this:

    'routes' => [
        [
            'pattern' => '(:all)',
            'action' => function ($id) {
                if (!kirby()->user()) {
                    return page('login');
                }
                $this->next();
            }
        ],
        [
            'pattern' => '(:all)/protected/(:any)',
            'action' => function ($pageId, $filename) {
                if (
                    kirby()->user() &&
                    ($page = page($pageId)) &&
                    $file = $page->files()->findBy('filename', $filename)
                ) {
                    return $file->read();
                }
                return site()->errorPage();
            }
        ],
        [
            'pattern' => 'logout',
            'action'  => function () {

                if ($user = kirby()->user()) {
                    $user->logout();
                }

                go('login');
            }
        ]
    ]
  • The first route takes care of pages.
  • The second route is for the files. We separate page id and filename by the string we inserted into the url in the file:url component.
  • If we can find a file, we return it with $file->read().

Note that with this approach, we don’t use any thumbs.

Great, thank you for your help!