New router and ability stuff.

This commit is contained in:
Floorb 2022-04-17 19:41:18 -04:00
parent 82dd103144
commit 26d00ce7b6
16 changed files with 112 additions and 91 deletions

View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
use PonePaste\Models\Paste;

View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');

View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');

View file

@ -0,0 +1,39 @@
<?php
namespace PonePaste\Helpers;
use PonePaste\Models\User;
use PonePaste\Models\Paste;
class AbilityHelper {
private const DESTRUCTIVE_ACTIONS = [
'edit', 'delete'
];
private User | null $user;
public function __construct(User | null $user) {
$this->user = $user;
}
public function can(string $action, mixed $subject) : bool {
if ($this->user === null) {
return false;
}
$is_destructive = in_array($action, self::DESTRUCTIVE_ACTIONS);
if (is_a($subject, 'Paste')) {
if (($subject->visible == Paste::VISIBILITY_PRIVATE) || $is_destructive) {
return $subject->user_id === $this->user->id;
}
return true;
}
if (is_a($subject, 'User')) {
return !$is_destructive || $subject->id === $this->user->id;
}
return false;
}
}

View file

@ -6,7 +6,6 @@ require_once(__DIR__ . '/../vendor/autoload.php');
require_once(__DIR__ . '/config.php');
require_once(__DIR__ . '/functions.php');
require_once(__DIR__ . '/passwords.php');
require_once(__DIR__ . '/DatabaseHandle.class.php');
use Illuminate\Database\Capsule\Manager as Capsule;
use PonePaste\Helpers\SessionHelper;
@ -14,6 +13,7 @@ use PonePaste\Models\IPBan;
use PonePaste\Models\PageView;
use PonePaste\Models\Paste;
use PonePaste\Models\User;
use PonePaste\Helpers\AbilityHelper;
/* View functions */
function javascriptIncludeTag(string $name) : string {
@ -242,6 +242,13 @@ $total_page_views = PageView::select('tpage')->orderBy('id', 'desc')->first()->t
$total_unique_views = PageView::select('tvisit')->orderBy('id', 'desc')->first()->tvisit;
$current_user = SessionHelper::currentUser();
$current_ability = new AbilityHelper($current_user);
function can(string $action, mixed $subject) : bool {
global $current_ability;
return $current_ability->can($action, $subject);
}
//SessionHelper::setupCsrfToken();

View file

@ -4,7 +4,6 @@ use PonePaste\Models\Paste;
use PonePaste\Models\Tag;
use PonePaste\Models\User;
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/captcha.php');
require_once('includes/functions.php');

View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');
require_once('includes/passwords.php');

View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');

View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');

105
paste.php
View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');
@ -44,40 +43,35 @@ updatePageViews();
$totalpastes = Paste::count();
$paste = Paste::find($paste_id);
$notfound = null;
$is_private = false;
$error = null;
if (!$paste) {
header('HTTP/1.1 404 Not Found');
$notfound = 'Not found';
$error = 'Not found';
goto Not_Valid_Paste;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!verifyCsrfToken()) {
$notfound = 'Invalid CSRF token (do you have cookies enabled?)';
$error = 'Invalid CSRF token (do you have cookies enabled?)';
goto Not_Valid_Paste;
}
}
/* $password_ok_pastes is an array of IDs of pastes for which a correct password has already been entered this session. */
if (isset($_SESSION['password_ok'])) {
$password_ok_pastes = json_decode($_SESSION['password_ok']);
} else {
$password_ok_pastes = [];
}
$paste_owner_id = $paste->user->id;
$paste_title = $paste->title;
$paste_code = $paste->code;
$using_highlighter = $paste_code !== 'pastedown';
$fav_count = $paste->favouriters()->count();
/*$paste = [
'title' => $paste_title,
'created_at' => $paste->created_at->format('jS F Y h:i:s A'),
'updated_at' => $paste->created_at->format('jS F Y h:i:s A'),
'user_id' => $paste_owner_id,
'views' => $row['views'],
'code' => $paste_code,
'tags' => getPasteTags($conn, $paste_id)
];*/
$p_content = $paste->content;
$p_visible = $paste->visible;
$p_expiry = $paste->expiry;
@ -87,15 +81,15 @@ $paste_is_favourited = $current_user !== null && $current_user->favourites->wher
$is_private = $p_visible === '2';
if ($is_private && (!$current_user || $current_user->id !== $paste_owner_id)) {
$notfound = 'This is a private paste. If you created this paste, please log in to view it.';
if (!can('view', $paste)) {
$error = 'This is a private paste. If you created this paste, please log in to view it.';
goto Not_Valid_Paste;
}
/* Paste deletion */
if (isset($_POST['delete'])) {
if (!$current_user || ($current_user->id !== $paste_owner_id)) {
$notfound = 'You cannot delete someone else\'s paste!';
if (!can('delete', $paste)) {
$error = 'You cannot delete someone else\'s paste!';
goto Not_Valid_Paste;
}
@ -108,37 +102,43 @@ if (isset($_POST['delete'])) {
/* Verify paste password */
$password_required = $p_password !== null && $p_password !== 'NONE';
$password_valid = true;
$password_candidate = '';
if ($password_required) {
if (!empty($_POST['mypass'])) {
$password_candidate = $_POST['mypass'];
} elseif (!empty($_GET['password'])) {
$password_candidate = @base64_decode($_GET['password']);
}
if (empty($password_candidate)) {
if ($password_required && !in_array($paste->id, $password_ok_pastes)) {
if (empty($_POST['mypass'])) {
$password_valid = false;
$error = 'This paste is password protected.';
goto Not_Valid_Paste;
} elseif (!pp_password_verify($password_candidate, $p_password)) {
} elseif (!pp_password_verify($_POST['mypass'], $p_password)) {
$password_valid = false;
$error = 'The provided password is incorrect.';
goto Not_Valid_Paste;
}
$password_ok_pastes[] = $paste->id;
$_SESSION['password_ok'] = json_encode($password_ok_pastes);
}
if (PP_MOD_REWRITE) {
$p_download = "download/$paste_id";
$p_raw = "raw/$paste_id";
$p_embed = "embed/$paste_id";
} else {
$p_download = "paste.php?download&id=$paste_id";
$p_raw = "paste.php?raw&id=$paste_id";
$p_embed = "paste.php?embed&id=$paste_id";
}
if (!empty($p_expiry) && $p_expiry !== 'SELF') {
$input_time = $p_expiry;
$current_time = mktime(date("H"), date("i"), date("s"), date("n"), date("j"), date("Y"));
if ($input_time < $current_time) {
$notfound = 'This paste has expired.';
$error = 'This paste has expired.';
goto Not_Valid_Paste;
}
}
/* handle favouriting */
if (isset($_POST['fave'])) {
if (isset($_POST['fave']) && $current_user) {
if ($paste_is_favourited) {
$current_user->favourites()->detach($paste);
} else {
@ -168,23 +168,12 @@ if (isset($_GET['raw'])) {
exit();
}
// Deletion
if (isset($_POST['delete'])) {
if (!$current_user || ($paste_owner_id !== $current_user->id)) {
flashError('You must be logged in and own this paste to delete it.');
} else {
$paste->delete();
flashSuccess('Paste deleted.');
header('Location: ' . urlForMember($current_user->username));
die();
}
}
// Preprocess
$highlight = array();
$highlight = [];
$prefix_size = strlen('!highlight!');
$lines = explode("\n", $p_content);
$p_content = "";
foreach ($lines as $idx => $line) {
if (substr($line, 0, $prefix_size) == '!highlight!') {
$highlight[] = $idx + 1;
@ -197,6 +186,7 @@ $p_content = rtrim($p_content);
// Apply syntax highlight
$p_content = htmlspecialchars_decode($p_content);
if ($paste_code === "pastedown") {
$parsedown = new Parsedown();
$parsedown->setSafeMode(true);
@ -214,24 +204,6 @@ if (isset($_GET['embed'])) {
exit();
}
if ($password_required && $password_valid) {
/* base64 here means that the password is exposed in the URL, technically - how to handle this better? */
$p_download = "paste.php?download&id=$paste_id&password=" . base64_encode($password_candidate);
$p_raw = "paste.php?raw&id=$paste_id&password=" . base64_encode($password_candidate);
$p_embed = "paste.php?embed&id=$paste_id&password=" . base64_encode($password_candidate);
} else {
// Set download URL
if (PP_MOD_REWRITE) {
$p_download = "download/$paste_id";
$p_raw = "raw/$paste_id";
$p_embed = "embed/$paste_id";
} else {
$p_download = "paste.php?download&id=$paste_id";
$p_raw = "paste.php?raw&id=$paste_id";
$p_embed = "paste.php?embed&id=$paste_id";
}
}
// View counter
if (!isRequesterLikelyBot() && @$_SESSION['not_unique'] !== $paste_id) {
$_SESSION['not_unique'] = $paste_id;
@ -243,14 +215,13 @@ $page_title = $paste->title;
$page_template = 'view';
$recommended_pastes = getUserRecommended($paste->user);
/* We arrive at this GOTO from various errors */
Not_Valid_Paste:
if ($is_private || $notfound || !$password_valid) {
// FIXME
// Display errors
if ($error) {
$page_title = 'Error';
$page_template = 'errors';
}
$csrf_token = setupCsrfToken();
require_once('theme/' . $default_theme . '/common.php');

View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');
require_once('includes/passwords.php');
@ -21,7 +20,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (!verifyCsrfToken()) {
$error = 'Invalid CSRF token (do you have cookies enabled?)';
} else if (isset($_POST['cpassword'])) {
$user_new_full = trim(htmlspecialchars($_POST['full']));
$user_old_pass = $_POST['old_password'];
if (pp_password_verify($user_old_pass, $user_password)) {
$user_new_cpass = pp_password_hash($_POST['password']);

18
router.php Normal file
View file

@ -0,0 +1,18 @@
<?php /** @noinspection PhpDefineCanBeReplacedWithConstInspection */
define('IN_PONEPASTE', 1);
const ROUTER_VALID_PAGES = [
'archive', 'discover', 'event', 'index', 'login',
'logout', 'pages', 'paste', 'profile', 'user'
];
if (empty($_GET['route'])) {
die('No route specified.');
}
if (!in_array($_GET['route'], ROUTER_VALID_PAGES)) {
die('Invalid route specified.');
}
/* This is safe, because this is whitelisted to the options above. */
require_once($_GET['route'] . '.php');

View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');

View file

@ -3,15 +3,10 @@
<div class="bd-main-container container">
<div class="bd-duo">
<div class="bd-lead">
<?php if (isset($notfound)) { ?>
<h1 class="subtitle is-4"><?= pp_html_escape($notfound) ?></h1>
<a href="./" class="btn btn-default">New Paste</a>
<?php } else { ?>
<h1 class="title is-5">This paste is password-protected.
<h1>
<?php if (isset($error)) { ?>
<?php if (isset($error)): ?>
<p class="help is-danger subtitle is-6"><?= pp_html_escape($error) ?></p>
<?php } ?>
<?php if ($password_required): ?>
<h1 class="title is-5">This paste is password-protected.</h1>
<form action="" method="post">
<div class="field has-addons">
<div class="control">
@ -22,7 +17,9 @@
</div>
<button type="submit" name="submit" class="button is-info">Submit</button>
</form>
<?php } ?>
<?php endif; ?>
<a href="/" class="btn btn-default">New Paste</a>
<?php endif; ?>
</div>
</div>
</div>

View file

@ -357,7 +357,7 @@ $selectedloader = "$bg[$i]"; // set variable equal to which random filename was
Encrypt on server (always enabled)
</label>
<?php
if ($current_user->id === $paste['user_id']) {
if (can('edit', $paste)) {
?>
<?php if (isset($csrf_token)): ?>
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>" />

View file

@ -1,5 +1,4 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');