All 16 include/ files now carry PURPOSE / DESIGN PRINCIPLES / OPERATIONAL SAFEGUARDS / EXPORTS / CONFIGURATION, keeping the first three section names identical to the bash headers so retrieval can route across both languages. monitor.php read six watchdog state files from /tmp while the watchdogs write to STATE_DIR, so every strike set came back empty and the summary reported healthy unconditionally. docs.php gained path containment before it is wired to a page.
107 lines
5.2 KiB
PHP
107 lines
5.2 KiB
PHP
<?php
|
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
|
// PURPOSE
|
|
// Renders the repo's own markdown — READMEs, Manuals, design notes — inside the WebGUI,
|
|
// substituting live conf values into `$VAR` markers so documentation shows what this host
|
|
// is actually configured to do rather than a generic example.
|
|
//
|
|
// STATUS
|
|
// Not currently wired. Nothing requires this file and there is no docs page or endpoint
|
|
// yet. It is kept because the per-folder README/Manual corpus is exactly what it exists to
|
|
// surface. Written to be safe on the day it is connected — see OPERATIONAL SAFEGUARDS.
|
|
//
|
|
// DESIGN PRINCIPLES
|
|
// Documentation is discovered, not enumerated.
|
|
// vv_docs_tree() walks SCRIPTS_DIR for *.md. A new folder README appears in the UI
|
|
// with no registration step, which is what keeps the docs from drifting out of the
|
|
// navigation.
|
|
//
|
|
// Live values, not example values.
|
|
// `$VAR_NAME` in a markdown file is replaced with that variable's current value from
|
|
// conf. Unresolved names render in a distinct class rather than being left as-is, so a
|
|
// stale variable reference in a doc is visible instead of looking like prose.
|
|
//
|
|
// Degrades to readable text without Parsedown.
|
|
// If the bundled renderer is absent the raw markdown is emitted in a <pre> block.
|
|
// Missing a formatter reduces presentation; it never hides the content.
|
|
//
|
|
// OPERATIONAL SAFEGUARDS
|
|
// Paths are contained to SCRIPTS_DIR.
|
|
// $rel is resolved with realpath() and required to remain under SCRIPTS_DIR, be a
|
|
// regular file, and carry a .md extension. This is deliberate defence for a parameter
|
|
// that will arrive from a request the moment this is wired up — without it, a
|
|
// traversal sequence reaches any file the web user can read.
|
|
//
|
|
// Markdown is rendered in safe mode.
|
|
// Parsedown runs with setSafeMode(true), and the <pre> fallback escapes everything.
|
|
// These files are trusted today, but they are also synced between hosts.
|
|
//
|
|
// Substituted conf values are escaped.
|
|
// htmlspecialchars() is applied to both the value and the variable name, so a conf
|
|
// value containing markup cannot inject into the rendered page.
|
|
//
|
|
// Read-only. Discovers and renders; never writes a doc.
|
|
//
|
|
// EXPORTS
|
|
// vv_docs_tree() every *.md under SCRIPTS_DIR, relative paths, sorted
|
|
// vv_docs_render() one file to HTML with conf substitution applied
|
|
//
|
|
// CONFIGURATION
|
|
// SCRIPTS_DIR the containment root and the discovery root
|
|
// PARSEDOWN_PATH /usr/local/emhttp/plugins/varaverk/lib/Parsedown.php — optional
|
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
|
|
|
require_once __DIR__ . '/config.php';
|
|
|
|
define('PARSEDOWN_PATH', '/usr/local/emhttp/plugins/varaverk/lib/Parsedown.php');
|
|
|
|
function vv_docs_tree(): array {
|
|
$base = SCRIPTS_DIR;
|
|
$tree = [];
|
|
$files = new RecursiveIteratorIterator(
|
|
new RecursiveDirectoryIterator($base, FilesystemIterator::SKIP_DOTS),
|
|
RecursiveIteratorIterator::SELF_FIRST
|
|
);
|
|
foreach ($files as $f) {
|
|
if ($f->isFile() && strtolower($f->getExtension()) === 'md') {
|
|
$rel = ltrim(str_replace($base, '', $f->getPathname()), '/');
|
|
$tree[] = $rel;
|
|
}
|
|
}
|
|
sort($tree);
|
|
return $tree;
|
|
}
|
|
|
|
function vv_docs_render(string $rel, array $vars): string {
|
|
// Containment check — $rel is expected to come from a request parameter once this is
|
|
// wired to a page. Resolve it and require the result to stay inside SCRIPTS_DIR and to
|
|
// still be a .md file, so a traversal sequence cannot reach arbitrary files.
|
|
$base = realpath(SCRIPTS_DIR);
|
|
$path = realpath(SCRIPTS_DIR . '/' . $rel);
|
|
if ($base === false || $path === false) return '<p>File not found.</p>';
|
|
if (!str_starts_with($path, $base . '/')) return '<p>File not found.</p>';
|
|
if (strtolower(pathinfo($path, PATHINFO_EXTENSION)) !== 'md') return '<p>File not found.</p>';
|
|
if (!is_file($path)) return '<p>File not found.</p>';
|
|
|
|
$md = file_get_contents($path);
|
|
|
|
// Substitute `$VAR_NAME` markers with live conf values
|
|
$md = preg_replace_callback('/`\$([A-Z0-9_]+)`/', function($m) use ($vars) {
|
|
$key = $m[1];
|
|
return isset($vars[$key])
|
|
? '<code class="vv-live-var">' . htmlspecialchars($vars[$key]) . '</code>'
|
|
: '<code class="vv-unknown-var">$' . htmlspecialchars($key) . '</code>';
|
|
}, $md);
|
|
|
|
// Render markdown
|
|
if (file_exists(PARSEDOWN_PATH)) {
|
|
require_once PARSEDOWN_PATH;
|
|
$pd = new Parsedown();
|
|
$pd->setSafeMode(true);
|
|
return $pd->text($md);
|
|
}
|
|
|
|
// Fallback: plain preformatted text
|
|
return '<pre>' . htmlspecialchars($md) . '</pre>';
|
|
}
|