PasteController

SOFT php Public Feb 27, 2026 07:21 AM
Share
<?php

namespace App\Http\Controllers;

use App\Models\Paste;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class PasteController extends Controller
{
    /**
     * Display the homepage / creation form.
     */
    public function create()
    {
        return view('pastes.create');
    }

    /**
     * Store a newly created paste in the database.
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'nullable|string|max:255',
            'content' => 'required|string|max:524288', // 512KB limit
            'syntax' => 'required|string',
            'visibility' => 'required|in:public,unlisted,private',
            'password' => 'nullable|string|min:4',
            'expiration_minutes' => 'nullable|integer'
        ]);

        $paste = Paste::create([
            'user_id' => auth()->id(), // Will be null if guest
            'slug' => Str::random(8),
            // Set a default title based on syntax or just 'Untitled Snippet'
            'title' => filled($validated['title']) ? $validated['title'] : 'Untitled ' . strtoupper($validated['syntax'] === 'plaintext' ? 'Snippet' : $validated['syntax']),
            'content' => $validated['content'],
            'syntax' => $validated['syntax'],
            'visibility' => $validated['visibility'],
            // Hash the password if one was provided
            'password' => filled($validated['password']) ? Hash::make($validated['password']) : null,
            // Calculate the expiration timestamp
            'expires_at' => $validated['expiration_minutes'] ? now()->addMinutes((int) $validated['expiration_minutes']) : null,
        ]);

        return redirect()->route('pastes.show', $paste);
    }

    /**
     * Display the specified paste.
     */
    public function show(Request $request, Paste $paste)
    {
        // 1. Check Privacy (If private, only the owner can see it)
        if ($paste->visibility === 'private' && $paste->user_id !== auth()->id()) {
            abort(403, 'This snippet is private and you do not have permission to view it.');
        }

        // 2. Check Password Protection
        if ($paste->password) {
            // Check if they have the unlock key in their active session
            if (!$request->session()->has("unlocked_paste_{$paste->id}")) {
                return view('pastes.unlock', compact('paste'));
            }
        }

        return view('pastes.show', compact('paste'));
    }

    /**
     * Handle the password submission to unlock a paste.
     */
    public function unlock(Request $request, Paste $paste)
    {
        $request->validate([
            'password' => 'required|string',
        ]);

        // Verify the typed password against the hashed database password
        if (Hash::check($request->password, $paste->password)) {
            // Grant access in the session
            $request->session()->put("unlocked_paste_{$paste->id}", true);

            return redirect()->route('pastes.show', $paste);
        }

        return back()->withErrors([
            'password' => 'The provided password was incorrect. Please try again.'
        ]);
    }

    /**
     * Delete the specified paste.
     */
    public function destroy(Paste $paste)
    {
        // Ensure the logged-in user actually owns this paste
        if ($paste->user_id !== auth()->id()) {
            abort(403, 'Unauthorized action.');
        }

        $paste->delete();

        return redirect()->route('dashboard')->with('success', 'Your snippet has been deleted successfully.');
    }
}