Update -> refactor and optimize UI , code ,...
This commit is contained in:
@@ -1,15 +1,22 @@
|
||||
<?php
|
||||
$env = parse_ini_file(__DIR__ . '/../../.env');
|
||||
$envFile = __DIR__ . '/../../.env';
|
||||
$env = file_exists($envFile) ? parse_ini_file($envFile) : [];
|
||||
|
||||
return [
|
||||
'db' => [
|
||||
'host' => $env['DB_HOST'] ?? 'localhost',
|
||||
'name' => $env['DB_NAME'] ?? 'paste',
|
||||
'user' => $env['DB_USER'] ?? 'root',
|
||||
'pass' => $env['DB_PASS'] ?? ''
|
||||
'host' => $env['DB_HOST'] ?? 'localhost',
|
||||
'name' => $env['DB_NAME'] ?? 'paste',
|
||||
'user' => $env['DB_USER'] ?? 'root',
|
||||
'pass' => $env['DB_PASS'] ?? '',
|
||||
'charset' => 'utf8mb4',
|
||||
],
|
||||
'redis' => [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379
|
||||
'host' => $env['REDIS_HOST'] ?? '127.0.0.1',
|
||||
'port' => (int)($env['REDIS_PORT'] ?? 6379),
|
||||
],
|
||||
'app' => [
|
||||
'master_key' => $env['MASTER_KEY'] ?? 'change_me_master_key',
|
||||
'base_url' => $env['APP_URL'] ?? '',
|
||||
'cipher' => 'AES-256-CBC',
|
||||
],
|
||||
'master_key' => $env['MASTER_KEY'] ?? 'change_me_master_key'
|
||||
];
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
<?php
|
||||
require __DIR__ . '/../core/security.php';
|
||||
$pdo = require __DIR__ . '/../core/db.php';
|
||||
require __DIR__ . '/../models/Paste.php';
|
||||
require_once __DIR__ . '/../core/security.php';
|
||||
$pdo = require __DIR__ . '/../core/db.php';
|
||||
require_once __DIR__ . '/../models/Paste.php';
|
||||
$config = require __DIR__ . '/../config/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: /index.php');
|
||||
header('Location: /');
|
||||
exit;
|
||||
}
|
||||
$text = $_POST['text'] ?? '';
|
||||
|
||||
$text = trim($_POST['text'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
$expire = isset($_POST['expire']) ? intval($_POST['expire']) : 0;
|
||||
if (trim($text) === '') {
|
||||
die('Text is required');
|
||||
$expire = isset($_POST['expire']) ? (int)$_POST['expire'] : 0;
|
||||
|
||||
if ($text === '') {
|
||||
jsonResponse(['success' => false, 'message' => 'Text cannot be empty.'], 422);
|
||||
}
|
||||
$id = generateId();
|
||||
$enc = encryptText($text, $config['master_key']);
|
||||
|
||||
$id = generateId();
|
||||
$enc = encryptText($text, $config['app']['master_key']);
|
||||
$password_hash = $password !== '' ? password_hash($password, PASSWORD_DEFAULT) : null;
|
||||
$expire_time = $expire > 0 ? time() + $expire : null;
|
||||
$expire_time = $expire > 0 ? time() + $expire : null;
|
||||
|
||||
$paste = new Paste($pdo);
|
||||
$paste->save($id, $enc['cipher'], $enc['iv'], $expire_time, $password_hash);
|
||||
|
||||
$paste->save($id, $enc['cipher'], $enc['iv'], $expire_time,$password_hash);
|
||||
$base = rtrim($config['app']['base_url'] ?: ('http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST']), '/');
|
||||
$url = $base . '/view/' . $id;
|
||||
|
||||
|
||||
$url = "http://" . $_SERVER['HTTP_HOST'] . "/view.php?id=" . $id;
|
||||
|
||||
echo json_encode([
|
||||
"success" => true,
|
||||
"url" => $url
|
||||
]);
|
||||
exit;
|
||||
jsonResponse(['success' => true, 'url' => $url]);
|
||||
|
||||
@@ -1,59 +1,56 @@
|
||||
<?php
|
||||
require __DIR__ . '/../core/security.php';
|
||||
$pdo = require __DIR__ . '/../core/db.php';
|
||||
require __DIR__ . '/../models/Paste.php';
|
||||
require_once __DIR__ . '/../core/security.php';
|
||||
$pdo = require __DIR__ . '/../core/db.php';
|
||||
require_once __DIR__ . '/../models/Paste.php';
|
||||
$config = require __DIR__ . '/../config/config.php';
|
||||
|
||||
$id = $_GET['id'] ?? '';
|
||||
$id = preg_replace('/[^a-f0-9]/i', '', $_GET['id'] ?? '');
|
||||
|
||||
if ($id === '') {
|
||||
$errorCode = 404;
|
||||
$errorMessage = 'Invalid paste ID.';
|
||||
require __DIR__ . '/../../public/error.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
$paste = new Paste($pdo);
|
||||
$data = $paste->get($id);
|
||||
$data = $paste->get($id);
|
||||
|
||||
if (!$data) {
|
||||
die('Paste not found.');
|
||||
$errorCode = 404;
|
||||
$errorMessage = 'Paste not found.';
|
||||
require __DIR__ . '/../../public/error.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($data['expire_time'] !== null && time() > (int)$data['expire_time']) {
|
||||
die('Paste has expired.');
|
||||
$errorCode = 410;
|
||||
$errorMessage = 'This paste has expired.';
|
||||
require __DIR__ . '/../../public/error.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($data['password_hash']) {
|
||||
if (!isset($_POST['password'])) {
|
||||
echo "<link rel='stylesheet' href='/assets/css/style.css'>";
|
||||
echo "<form method='post'>";
|
||||
echo "<input type='password' class='usepassword' name='password' placeholder='Password'>";
|
||||
echo "<button type='submit'>View</button>";
|
||||
echo "</form>";
|
||||
$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;
|
||||
} else {
|
||||
$wrongPassword = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$needsPassword) {
|
||||
$decrypted = decryptText($data['encrypted_text'], $data['iv'], $config['app']['master_key']);
|
||||
if ($decrypted === false) {
|
||||
$errorCode = 500;
|
||||
$errorMessage = 'Decryption failed. The paste may be corrupted.';
|
||||
require __DIR__ . '/../../public/error.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!password_verify($_POST['password'], $data['password_hash'])) {
|
||||
die('Wrong password.');
|
||||
}
|
||||
}
|
||||
|
||||
$decrypted = decryptText($data['encrypted_text'], $data['iv'], $config['master_key']);
|
||||
|
||||
if ($decrypted === false) {
|
||||
die('Decryption failed.');
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>View Paste</title>
|
||||
<link rel="stylesheet" href="/assets/css/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Your Paste</h1>
|
||||
<div class="paste-box">
|
||||
<button id="copyBtn">Copy</button>
|
||||
<pre id="pasteContent"><?= htmlspecialchars($decrypted) ?></pre>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,13 +1,21 @@
|
||||
<?php
|
||||
$config = require __DIR__ . '/../config/config.php';
|
||||
|
||||
try {
|
||||
$pdo = new PDO(
|
||||
"mysql:host={$config['db']['host']};dbname={$config['db']['name']};charset=utf8mb4",
|
||||
$config['db']['user'],
|
||||
$config['db']['pass'],
|
||||
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
|
||||
$dsn = sprintf(
|
||||
'mysql:host=%s;dbname=%s;charset=%s',
|
||||
$config['db']['host'],
|
||||
$config['db']['name'],
|
||||
$config['db']['charset']
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
die('Database connection error');
|
||||
$pdo = new PDO($dsn, $config['db']['user'], $config['db']['pass'], [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
]);
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(503);
|
||||
die(json_encode(['success' => false, 'message' => 'Database connection error.']));
|
||||
}
|
||||
|
||||
return $pdo;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<?php
|
||||
|
||||
function redisClient()
|
||||
function redisClient(): Redis
|
||||
{
|
||||
static $redis = null;
|
||||
if ($redis === null) {
|
||||
$config = require __DIR__ . '/../config/config.php';
|
||||
|
||||
$redis = new Redis();
|
||||
$redis->connect($config['redis']['host'], $config['redis']['port']);
|
||||
$redis = new Redis();
|
||||
if (!@$redis->connect($config['redis']['host'], $config['redis']['port'])) {
|
||||
throw new RuntimeException('Redis connection failed.');
|
||||
}
|
||||
}
|
||||
return $redis;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,32 @@
|
||||
<?php
|
||||
function encryptText($text, $key) {
|
||||
$iv = random_bytes(16);
|
||||
|
||||
function encryptText(string $text, string $key): array
|
||||
{
|
||||
$iv = random_bytes(16);
|
||||
$cipher = openssl_encrypt($text, 'AES-256-CBC', $key, 0, $iv);
|
||||
if ($cipher === false) {
|
||||
throw new RuntimeException('Encryption failed.');
|
||||
}
|
||||
return [
|
||||
'cipher' => $cipher,
|
||||
'iv' => base64_encode($iv)
|
||||
'iv' => base64_encode($iv),
|
||||
];
|
||||
}
|
||||
function decryptText($cipher, $iv, $key) {
|
||||
|
||||
function decryptText(string $cipher, string $iv, string $key): string|false
|
||||
{
|
||||
return openssl_decrypt($cipher, 'AES-256-CBC', $key, 0, base64_decode($iv));
|
||||
}
|
||||
function generateId() {
|
||||
|
||||
function generateId(): string
|
||||
{
|
||||
return bin2hex(random_bytes(16));
|
||||
}
|
||||
|
||||
function jsonResponse(array $data, int $status = 200): void
|
||||
{
|
||||
http_response_code($status);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data);
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -1,62 +1,58 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../core/db.php';
|
||||
require_once __DIR__ . '/../core/redis.php';
|
||||
|
||||
require_once __DIR__ . '/../core/redis.php';
|
||||
|
||||
class Paste
|
||||
{
|
||||
private $pdo;
|
||||
public function __construct($pdo)
|
||||
private PDO $pdo;
|
||||
|
||||
public function __construct(PDO $pdo)
|
||||
{
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function save($id, $encrypted_text, $iv, $expire_time, $password_hash)
|
||||
{
|
||||
if ($expire_time === null) {
|
||||
$stmt = $this->pdo->prepare("INSERT INTO pastes(id, encrypted_text, iv, expire_time, password_hash)
|
||||
VALUES (?, ?, ?, NULL, ?)");
|
||||
return $stmt->execute([$id, $encrypted_text, $iv, $password_hash]);
|
||||
public function save(
|
||||
string $id,
|
||||
string $encrypted_text,
|
||||
string $iv,
|
||||
?int $expire_time,
|
||||
?string $password_hash
|
||||
): bool {
|
||||
if ($expire_time !== null) {
|
||||
$ttl = max(1, $expire_time - time());
|
||||
$redis = redisClient();
|
||||
$redis->setex("paste:{$id}", $ttl, json_encode([
|
||||
'encrypted_text' => $encrypted_text,
|
||||
'iv' => $iv,
|
||||
'password_hash' => $password_hash,
|
||||
]));
|
||||
return true;
|
||||
}
|
||||
|
||||
$redis = redisClient();
|
||||
|
||||
$expire_time = (int)$expire_time;
|
||||
$ttl = max(1, $expire_time - time());
|
||||
|
||||
|
||||
$redis->setex(
|
||||
"paste:$id",
|
||||
$ttl,
|
||||
json_encode([
|
||||
'encrypted_text' => $encrypted_text,
|
||||
'iv' => $iv,
|
||||
'password_hash' => $password_hash
|
||||
])
|
||||
$stmt = $this->pdo->prepare(
|
||||
'INSERT INTO pastes (id, encrypted_text, iv, expire_time, password_hash)
|
||||
VALUES (?, ?, ?, NULL, ?)'
|
||||
);
|
||||
|
||||
|
||||
return true;
|
||||
return $stmt->execute([$id, $encrypted_text, $iv, $password_hash]);
|
||||
}
|
||||
|
||||
|
||||
public function get($id)
|
||||
public function get(string $id): array|false
|
||||
{
|
||||
$redis = redisClient();
|
||||
$raw = $redis->get("paste:{$id}");
|
||||
|
||||
$data = $redis->get("paste:$id");
|
||||
if ($data !== false) {
|
||||
$json = json_decode($data, true);
|
||||
if ($raw !== false) {
|
||||
$json = json_decode($raw, true);
|
||||
return [
|
||||
'encrypted_text' => $json['encrypted_text'],
|
||||
'iv' => $json['iv'],
|
||||
'password_hash' => $json['password_hash'],
|
||||
'expire_time' => time() + $redis->ttl("paste:$id")
|
||||
'iv' => $json['iv'],
|
||||
'password_hash' => $json['password_hash'],
|
||||
'expire_time' => time() + $redis->ttl("paste:{$id}"),
|
||||
];
|
||||
}
|
||||
|
||||
$stmt = $this->pdo->prepare("SELECT * FROM pastes WHERE id = ?");
|
||||
$stmt = $this->pdo->prepare('SELECT * FROM pastes WHERE id = ? LIMIT 1');
|
||||
$stmt->execute([$id]);
|
||||
return $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $stmt->fetch();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user