Add -> add project

This commit is contained in:
2026-03-27 14:09:52 +03:30
commit 3327207f05
14 changed files with 403 additions and 0 deletions

15
app/config/config.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
$env = parse_ini_file(__DIR__ . '/../../.env');
return [
'db' => [
'host' => $env['DB_HOST'] ?? 'localhost',
'name' => $env['DB_NAME'] ?? 'paste',
'user' => $env['DB_USER'] ?? 'root',
'pass' => $env['DB_PASS'] ?? ''
],
'redis' => [
'host' => '127.0.0.1',
'port' => 6379
],
'master_key' => $env['MASTER_KEY'] ?? 'change_me_master_key'
];

View File

@@ -0,0 +1,31 @@
<?php
require __DIR__ . '/../core/security.php';
$pdo = require __DIR__ . '/../core/db.php';
require __DIR__ . '/../models/Paste.php';
$config = require __DIR__ . '/../config/config.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: /index.php');
exit;
}
$text = $_POST['text'] ?? '';
$password = $_POST['password'] ?? '';
$expire = isset($_POST['expire']) ? intval($_POST['expire']) : 0;
if (trim($text) === '') {
die('Text is required');
}
$id = generateId();
$enc = encryptText($text, $config['master_key']);
$password_hash = $password !== '' ? password_hash($password, PASSWORD_DEFAULT) : null;
$expire_time = $expire > 0 ? time() + $expire : null;
$paste = new Paste($pdo);
$paste->save($id, $enc['cipher'], $enc['iv'], $expire_time,$password_hash);
$url = "http://" . $_SERVER['HTTP_HOST'] . "/view.php?id=" . $id;
echo json_encode([
"success" => true,
"url" => $url
]);
exit;

View File

@@ -0,0 +1,59 @@
<?php
require __DIR__ . '/../core/security.php';
$pdo = require __DIR__ . '/../core/db.php';
require __DIR__ . '/../models/Paste.php';
$config = require __DIR__ . '/../config/config.php';
$id = $_GET['id'] ?? '';
$paste = new Paste($pdo);
$data = $paste->get($id);
if (!$data) {
die('Paste not found.');
}
if ($data['expire_time'] !== null && time() > (int)$data['expire_time']) {
die('Paste has expired.');
}
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>";
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>

13
app/core/db.php Normal file
View File

@@ -0,0 +1,13 @@
<?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]
);
} catch (Exception $e) {
die('Database connection error');
}
return $pdo;

13
app/core/redis.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
function redisClient()
{
static $redis = null;
if ($redis === null) {
$config = require __DIR__ . '/../config/config.php';
$redis = new Redis();
$redis->connect($config['redis']['host'], $config['redis']['port']);
}
return $redis;
}

15
app/core/security.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
function encryptText($text, $key) {
$iv = random_bytes(16);
$cipher = openssl_encrypt($text, 'AES-256-CBC', $key, 0, $iv);
return [
'cipher' => $cipher,
'iv' => base64_encode($iv)
];
}
function decryptText($cipher, $iv, $key) {
return openssl_decrypt($cipher, 'AES-256-CBC', $key, 0, base64_decode($iv));
}
function generateId() {
return bin2hex(random_bytes(16));
}

62
app/models/Paste.php Normal file
View File

@@ -0,0 +1,62 @@
<?php
require_once __DIR__ . '/../core/db.php';
require_once __DIR__ . '/../core/redis.php';
class Paste
{
private $pdo;
public function __construct($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]);
}
$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
])
);
return true;
}
public function get($id)
{
$redis = redisClient();
$data = $redis->get("paste:$id");
if ($data !== false) {
$json = json_decode($data, true);
return [
'encrypted_text' => $json['encrypted_text'],
'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->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
}