Building a Secure Livewire File Explorer with TinyMCE and Sortable.js

Learn to create a secure file explorer in Laravel using Livewire, TinyMCE for rich text editing, and Sortable.js for drag-and-drop functionality.

Building a Secure Livewire File Explorer with TinyMCE and Sortable.js

If you’re like many developers working with Laravel, you’ve probably encountered the challenge of creating a secure file explorer for your application. You want to give users the ability to upload and manage files, but you also need to ensure that sensitive data is protected from unauthorized access. Perhaps you’ve tried using built-in file management tools or third-party libraries, only to find that they lack the flexibility and security features you need.

You’ll build a robust and secure file explorer with TinyMCE for rich text editing and Sortable.js for drag-and-drop functionality. By the end of this tutorial, you’ll have created a Livewire component that integrates both libraries seamlessly, allowing users to upload, organize, and view files in a user-friendly interface. You’ll also learn how to configure file storage in Laravel and secure the explorer with authentication and authorization.

Step 1: Installing Required Packages and Dependencies

To begin building our secure file explorer, we need to install the required packages and dependencies. We’ll be using TinyMCE for rich text editing, Sortable.js for drag-and-drop functionality, and Livewire for creating a secure file explorer component.

First, let’s create a new Laravel project or navigate to an existing one in the terminal:

composer create-project --prefer-dist laravel/laravel secure-file-explorer

Navigate into your project directory:

cd secure-file-explorer

Next, we’ll install the required packages using Composer. We need TinyMCE and Sortable.js, which are not included in Laravel by default.

composer require tinymce/tinymce-php-sortablejs

This will install both TinyMCE and Sortable.js along with their dependencies.

In our config/app.php file, we’ll register the service providers for these packages. Add the following lines to the $providers array:

'providers' => [
    // ...
    \TinyMCE\Providers\TinyMCEServiceProvider::class,
    \SortableJS\SortableJsServiceProvider::class,
],

Finally, publish the package’s assets by running:

php artisan vendor:publish --provider="TinyMCE\Providers\TinyMCEServiceProvider"
php artisan vendor:publish --provider="SortableJS\SortableJsServiceProvider"

This will install and configure TinyMCE and Sortable.js in our Laravel project. In the next section, we’ll set up TinyMCE for rich text editing.

Setting Up TinyMCE for Rich Text Editing

To enable rich text editing in our file explorer, we’ll use the popular TinyMCE library. First, install the package using Composer:

composer require tinymce/tinymce-php

Next, configure the library by publishing its configuration file and updating it to match your needs:

php artisan vendor:publish --provider="TinyMCE\\TinyMCE ServiceProvider"

Then, edit the config/tiny-mce.php file to set up your TinyMCE settings. For example, you can enable or disable plugins like advlist, autosave, and fullscreen. Here’s an updated excerpt:

'tinymce' => [
    'selector' => '#editor',
    'plugins' => [
        'advlist autolink autosave link image lists charmap print preview hr anchor pagebreak',
        'searchreplace wordcount visualblocks visualchars code fullscreen,
        'insertdatetime media table paste code help wordcount',
    ],
],

In your Blade template, you can now create a TinyMCE editor instance:

{!! tinymceInit('my-editor') !!}

Replace my-editor with the ID of your HTML element where the TinyMCE editor will be rendered.

Finally, update the tinymce-init.blade.php file in the published package directory to render the TinyMCE editor:

@push('scripts')
    <script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script>
    <script>
        tinymce.init({
            selector: '#editor',
            // other settings...
        });
    </script>
@endpush

With TinyMCE up and running, we can now focus on implementing drag-and-drop functionality with Sortable.js.

Implementing Sortable.js for Drag-and-Drop Functionality

To enable drag-and-drop functionality in our file explorer, we’ll be using Sortable.js. This library provides a simple and lightweight way to reorder items on a webpage.

First, install Sortable.js via npm by running the following command in your terminal:

npm install sortablejs

Next, update your app.js file to include the Sortable.js script:

// app.js

require(__DIR__ . '/../vendor/autoload.php');

use Illuminate\Support\Facades\Route;

Route::group([
    'namespace' => \App\Http\Controllers,
], function () {
    Route::get('/file-explorer', FileExplorerController::class)->name('file-explorer.index');
});

// Include Sortable.js script
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>

Now, let’s implement the drag-and-drop functionality in our FileExplorerController. We’ll use the sortable directive to enable reordering of files:

// FileExplorerController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Livewire\Component;

class FileExplorerController extends Component
{
    public function render()
    {
        return view('file-explorer');
    }
}

// In file-explorer.blade.php, add the following code:
<div wire:sortable="files" x-data>
    @foreach($files as $file)
        <div wire:sortable-item={{ $file->id }}>
            {{ $file->name }}
        </div>
    @endforeach
</div>

<script>
    Sortable.create(document.querySelector('.files'), {
        handle: '.handle',
    });
</script>

This code enables drag-and-drop functionality for files in our file explorer, allowing users to reorder them as needed. With this feature implemented, we’re one step closer to building a comprehensive and user-friendly file explorer.

Creating a Secure File Explorer Component with Livewire

In this step, we’ll create a secure file explorer component using Laravel’s Livewire package. We’ll use it to display and manage files in our application.

First, let’s install the necessary packages by running:

composer require livewire/livewire

Next, create a new Livewire component named FileExplorer inside the app/Http/Livewire directory:

// app/Http/Livewire/FileExplorer.php

namespace App\Http\Livewire;

use Illuminate\Support\Facades Storage;
use Livewire\Component;

class FileExplorer extends Component
{
    public $files = [];

    protected $listeners = ['refreshFiles'];

    public function render()
    {
        return view('livewire.file-explorer');
    }

    public function refreshFiles($directory)
    {
        $this->files = collect(Storage::disk('public')->files($directory))->mapWithKeys(function ($file) {
            return [$file => basename($file)];
        })->toArray();
    }
}

We’ll also create a new Blade view for our component:

// resources/views/livewire/file-explorer.blade.php

<div>
    <ul>
        @foreach($files as $file)
            <li>{{ $file }} ({{ Storage::size($file) }})</li>
        @endforeach
    </ul>

    <button wire:click="refreshFiles('path/to/directory')">Refresh Files</button>
</div>

Make sure to update your web.php route file to include the Livewire component:

// routes/web.php

use App\Http\Livewire\FileExplorer;

Route::livewire('/file-explorer', FileExplorer::class);

This is a basic implementation of our secure file explorer component using Livewire. We’ll continue building upon this in the next sections to add more features and functionality.

The FileExplorer component now displays a list of files stored in the public disk, with a button to refresh the list. The $files property is updated whenever the refreshFiles method is triggered, which uses Laravel’s Storage facade to fetch the latest file listing from the specified directory.

Integrating AI-Powered Malware Detection (Optional)

To further enhance security in our file explorer, we can integrate an AI-powered malware detection service. This optional step requires a subscription to a cloud-based API like Google Cloud’s VirusTotal or AWS Marketplace’s Malwarebytes.

For this example, let’s assume you have already obtained an API key for VirusTotal. Create a new Laravel package to handle the integration:

// app/Providers/VirusTotalServiceServiceProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use GuzzleHttp\Client;

class VirusTotalServiceServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // Register the service instance in the IoC container
        $this->app->singleton('virus_total_service', function ($app) {
            return new VirusTotalService($app['config']->get('services.virus-total.api_key'));
        });
    }
}
// app/Services/VirusTotalService.php

namespace App\Services;

use GuzzleHttp\Client;
use Illuminate\Support\Facades\Http;

class VirusTotalService
{
    private $apiKey;

    public function __construct($apiKey)
    {
        $this->apiKey = $apiKey;
    }

    public function scanFile(string $fileHash): array
    {
        $client = new Client();
        $response = $client->get('https://virustotal.com/api/v3/files/' . $fileHash, [
            'headers' => ['x-apikey' => $this->apiKey],
        ]);

        return json_decode($response->getBody()->getContents(), true);
    }
}

To use the service in our file explorer component, inject it into the controller:

// app/Http/Livewire/FileExplorerController.php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Services\VirusTotalService;

class FileExplorerController extends Component
{
    private $virusTotalService;

    public function __construct(VirusTotalService $virusTotalService)
    {
        $this->virusTotalService = $virusTotalService;
    }

    // ...
}

This integration adds an extra layer of protection against malware, but keep in mind that it’s not a replacement for traditional security measures.

With this step complete, our file explorer is now even more secure and robust. Next up, we’ll configure file upload and storage using Laravel.

Configuring File Upload and Storage in Laravel

To store and manage uploaded files securely, we’ll configure Laravel’s built-in file system abstraction layer. Create a new file filesystems.php in the config directory:

// config/filesystems.php

'default' => env('FILESYSTEM_DRIVER', 'local'),

'disks' => [
    'public' => [
        'driver' => 'local',
        'root' => public_path('/'),
    ],
    'private' => [
        'driver' => 'local',
        'root' => storage_path('/app/files'),
    ],
],

Next, define the file upload logic in a service provider. Create a new file FileUploaderServiceProvider.php in the app/Providers directory:

// app/Providers/FileUploaderServiceProvider.php

namespace App\Providers;

use Illuminate\Support\Facades\Storage;
use Illuminate\Support\ServiceProvider;

class FileUploaderServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Storage::extend('private', function ($application, $config) {
            return new PrivateFileStorage($config['root']);
        });
    }
}

Finally, in the FileExplorer component, inject the file uploader instance and use it to handle file uploads:

// app/Http/Livewire/FileExplorer.php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Providers\FileUploaderServiceProvider;

class FileExplorer extends Component
{
    public $file;

    public function render()
    {
        return view('livewire.file-explorer');
    }

    public function uploadFile()
    {
        if ($this->file) {
            Storage::disk('private')->putFileAs(
                'uploads',
                request()->file('file'),
                time() . '.' . $this->file->getClientOriginalExtension(),
            );
            // Process the uploaded file...
        }
    }
}

This sets up a basic file upload and storage system using Laravel’s filesystem package.

Securing the File Explorer with Authentication and Authorization

Now that our file explorer component is up and running, it’s essential to ensure that only authorized users can access and interact with files. We’ll achieve this by integrating Laravel’s built-in authentication and authorization features.

First, let’s add the auth middleware to our web routes in routes/web.php. This will automatically authenticate incoming requests:

Route::middleware('auth')->group(function () {
    // File explorer routes go here...
});

Next, we need to define permissions for our file explorer component. We’ll create a new policy called FileExplorerPolicy in the app/Policies directory:

// app/Policies/FileExplorerPolicy.php

namespace App\Policies;

use App\Models\File;
use Illuminate\Auth\Access\HandlesAuthorization;

class FileExplorerPolicy implements HandlesAuthorization
{
    public function viewAny(User $user)
    {
        // Allow users to view files if they're authenticated and have the 'file.view' permission
        return $user->hasPermissionTo('file.view');
    }

    public function upload(File $file, User $user)
    {
        // Allow users to upload files if they're authenticated and have the 'file.upload' permission
        return $user->hasPermissionTo('file.upload');
    }
}

Finally, we’ll update our FileExplorer Livewire component to use these permissions:

// resources/views/file-explorer.blade.php

@can('viewAny', File::class)
    // Display file list...
@endcan

@can('upload', File::class)
    // Render upload form...
@endcan

With these changes in place, only authorized users will be able to access and interact with files in our secure file explorer. This ensures that sensitive data remains protected at all times.

This concludes our comprehensive tutorial on building a secure file explorer with TinyMCE and Sortable.js. With this final piece of the puzzle in place, you’re now ready to deploy your own production-ready file explorer application!

Testing and Deploying the Secure File Explorer

Now that our secure file explorer is built and secured with authentication and authorization, it’s time to put it through its paces.

First, let’s test our file explorer component locally using the following command in your terminal:

php artisan serve

Navigate to http://localhost:8000 in your web browser. You should see the file explorer component displayed with all files and directories listed.

To test drag-and-drop functionality, sort file orders, and upload new files, use the TinyMCE editor’s toolbar buttons or drag files from your local machine onto the file list area.

For more comprehensive testing, I recommend using Laravel’s built-in testing features. Create a new test class in tests/Unit directory, for example FileExplorerTest.php. You can then write unit tests to verify that each functionality works as expected:

namespace Tests\Unit;

use Illuminate\Foundation\Testing\TestCase;
use App\Models\File;
use Livewire\Livewire;

class FileExplorerTest extends TestCase
{
    public function test_file_list_loads_properly()
    {
        $response = $this->get('/file-explorer');
        $response->assertStatus(200);
    }

    public function test_drag_and_drop_functionality()
    {
        // Setup TinyMCE editor with a file list
        $component = Livewire::test('file-explorer');

        // Simulate drag-and-drop event
        $component->callMethod('dragAndDropFile', ['new_file.txt']);

        // Assert that new file is added to the list
        $this->assertDatabaseHas('files', ['name' => 'new_file.txt']);
    }
}

Once you’re satisfied with your testing results, it’s time to deploy your secure file explorer to a production environment. Follow standard Laravel deployment procedures using tools like composer and php artisan.

Frequently Asked Questions

What is the best alternative to TinyMCE for rich text editing in a Laravel application?

Other popular alternatives to TinyMCE include CKEditor and Quill, which offer similar features and flexibility. However, TinyMCE’s extensive plugin library and customization options make it a strong choice for many developers.

Why do I need to publish the package assets using php artisan vendor:publish?

Publishing the package assets is necessary to install and configure TinyMCE and Sortable.js in your Laravel project. This step ensures that the libraries are properly registered and their assets are available for use.

How do I prevent unauthorized access to sensitive data in my file explorer?

To secure your file explorer, you should implement authentication and authorization using Laravel’s built-in features. This includes setting up user roles and permissions, as well as configuring file storage and access controls.

What is the purpose of installing Sortable.js separately from TinyMCE?

Sortable.js provides drag-and-drop functionality for your file explorer, allowing users to reorder files without requiring manual intervention. Installing it separately gives you more control over its configuration and customization.

Comments

comments