Files
safe-paste/app/controllers/ViewController.php

82 lines
2.8 KiB
PHP

<?php
require_once __DIR__ . '/../core/security.php';
require_once __DIR__ . '/../core/logger.php';
$pdo = require __DIR__ . '/../core/db.php';
require_once __DIR__ . '/../models/Paste.php';
require_once __DIR__ . '/../models/Analytics.php';
$config = require __DIR__ . '/../config/config.php';
$logger = new Logger('view');
$analytics = new Analytics($pdo);
$id = preg_replace('/[^a-f0-9]/i', '', $_GET['id'] ?? '');
if ($id === '') {
$logger->warning('View request with invalid or missing paste ID', ['raw_id' => $_GET['id'] ?? '']);
$analytics->record('paste_not_found', null, ['reason' => 'invalid_id']);
$errorCode = 404;
$errorMessage = 'Invalid paste ID.';
require __DIR__ . '/../../public/error.php';
exit;
}
$paste = new Paste($pdo);
$data = $paste->get($id);
if (!$data) {
$logger->info('Paste not found', ['id' => $id]);
$analytics->record('paste_not_found', $id);
$errorCode = 404;
$errorMessage = 'Paste not found.';
require __DIR__ . '/../../public/error.php';
exit;
}
if ($data['expire_time'] !== null && time() > (int)$data['expire_time']) {
$logger->info('Expired paste accessed', ['id' => $id, 'expired_at' => $data['expire_time']]);
$analytics->record('paste_expired', $id, ['expired_at' => $data['expire_time']]);
$errorCode = 410;
$errorMessage = 'This paste has expired.';
require __DIR__ . '/../../public/error.php';
exit;
}
$needsPassword = (bool)$data['password_hash'];
$wrongPassword = false;
$decrypted = null;
if ($needsPassword) {
$submitted = $_POST['password'] ?? null;
if ($submitted !== null) {
if (password_verify($submitted, $data['password_hash'])) {
$needsPassword = false;
$logger->info('Paste unlocked successfully', ['id' => $id]);
$analytics->record('paste_unlocked', $id);
} else {
$wrongPassword = true;
$logger->warning('Failed password attempt for paste', ['id' => $id]);
$analytics->record('paste_failed_password', $id);
}
} else {
$analytics->record('paste_password_prompt', $id);
}
}
if (!$needsPassword) {
$decrypted = decryptText($data['encrypted_text'], $data['iv'], $config['app']['master_key']);
if ($decrypted === false) {
$logger->error('Decryption failed for paste', ['id' => $id]);
$analytics->record('paste_decrypt_error', $id);
$errorCode = 500;
$errorMessage = 'Decryption failed. The paste may be corrupted.';
require __DIR__ . '/../../public/error.php';
exit;
}
$logger->info('Paste viewed', ['id' => $id, 'char_count' => mb_strlen($decrypted, 'UTF-8')]);
$analytics->record('paste_viewed', $id, [
'char_count' => mb_strlen($decrypted, 'UTF-8'),
'has_expiry' => $data['expire_time'] !== null,
]);
}