Files
luxtools-plugin/scratchpad.php

127 lines
3.6 KiB
PHP

<?php
// phpcs:disable PSR1.Files.SideEffects.FoundWithSymbols
use dokuwiki\plugin\luxtools\Path;
use dokuwiki\plugin\luxtools\ScratchpadMap;
if (!defined('DOKU_INC')) define('DOKU_INC', __DIR__ . '/../../../');
require_once(DOKU_INC . 'inc/init.php');
global $INPUT;
$syntax = plugin_load('syntax', 'luxtools');
if (!$syntax) {
http_status(500);
header('Content-Type: application/json');
echo json_encode(['ok' => false, 'error' => 'plugin disabled']);
exit;
}
/**
* Send a JSON response.
*
* @param int $status
* @param array $payload
* @return void
*/
function luxtools_scratchpad_json(int $status, array $payload): void
{
http_status($status);
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
echo json_encode($payload);
exit;
}
$cmd = (string)$INPUT->str('cmd');
$pad = (string)$INPUT->str('pad');
$pageId = (string)$INPUT->str('id');
if (function_exists('cleanID')) {
$pageId = cleanID($pageId);
}
if ($cmd === '' || $pad === '' || $pageId === '') {
luxtools_scratchpad_json(400, ['ok' => false, 'error' => 'missing parameters']);
}
// Require the user to at least be able to read the host page.
if (function_exists('auth_quickaclcheck') && auth_quickaclcheck($pageId) < AUTH_READ) {
luxtools_scratchpad_json(403, ['ok' => false, 'error' => 'forbidden']);
}
$map = new ScratchpadMap((string)$syntax->getConf('scratchpad_paths'));
try {
$resolved = (string)$map->resolve($pad);
if ($resolved === '' || str_ends_with($resolved, '/')) {
throw new Exception('Invalid scratchpad path');
}
// Never allow writing/reading within DokuWiki-controlled paths.
if (Path::isWikiControlled(Path::cleanPath($resolved, false))) {
throw new Exception('Access to wiki files is not allowed');
}
} catch (Exception $e) {
luxtools_scratchpad_json(403, ['ok' => false, 'error' => 'access denied']);
}
if ($cmd === 'load') {
$text = '';
$exists = @is_file($resolved);
if ($exists) {
if (!@is_readable($resolved)) {
luxtools_scratchpad_json(500, ['ok' => false, 'error' => 'unreadable']);
}
$read = io_readFile($resolved, false);
if ($read === false) {
luxtools_scratchpad_json(500, ['ok' => false, 'error' => 'unreadable']);
}
$text = (string)$read;
}
luxtools_scratchpad_json(200, ['ok' => true, 'text' => $text]);
}
if ($cmd === 'save') {
if (strtoupper($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
luxtools_scratchpad_json(405, ['ok' => false, 'error' => 'method not allowed']);
}
// Require edit permission on the host page.
if (function_exists('auth_quickaclcheck') && auth_quickaclcheck($pageId) < AUTH_EDIT) {
luxtools_scratchpad_json(403, ['ok' => false, 'error' => 'forbidden']);
}
if (!checkSecurityToken()) {
luxtools_scratchpad_json(403, ['ok' => false, 'error' => 'bad token']);
}
$text = (string)$INPUT->str('text');
// Ensure directory exists
$dir = dirname($resolved);
if (function_exists('io_mkdir_p')) {
io_mkdir_p($dir);
} elseif (!@is_dir($dir)) {
@mkdir($dir, 0777, true);
}
$ok = false;
if (function_exists('io_saveFile')) {
$ok = (bool)io_saveFile($resolved, $text);
} else {
$ok = @file_put_contents($resolved, $text, LOCK_EX) !== false;
}
if (!$ok) {
luxtools_scratchpad_json(500, ['ok' => false, 'error' => 'save failed']);
}
luxtools_scratchpad_json(200, ['ok' => true]);
}
luxtools_scratchpad_json(400, ['ok' => false, 'error' => 'unknown command']);