Files
provision_sccp/lib/resolve.php
Diederik de Groot 3e9f731e9a Make config instantiation private
Fixup Paths
Moved all tests to phpunit tests

Signed-off-by: Diederik de Groot <ddegroot@talon.nl>
2020-03-18 11:57:30 +01:00

152 lines
4.6 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace SCCP\Resolve;
include_once("config.php");
include_once("utils.php");
include_once("resolveCache.php");
use SCCP\Utils as Utils;
use SCCP\ResolveCache as ResolveCache;
/* Todo:
✔️ setup logging
✔️ read config.file
✔? improve error handling
✔️? secure urlencoding/urldecoding
✔️? don't allow browsing
- check source ip-range
- check HTTPHeader for known BrowserTypes
- Could use some more test-cases, especially error ones
*/
//class ResolveResult extends Enum {
class ResolveResult {
const Ok = 0;
const EmptyRequest = 1;
const RequestNotAString = 2;
const RequestContainsInvalidChar = 3;
const RequestContainsPathWalk = 4;
const FileNotFound = 5;
const InvalidFilename = 6;
const InvalidPath = 7;
}
class Resolve {
private $isDirty = FALSE;
private $cache;
private $config;
function __construct($config) {
$this->config = $config;
$this->cache = new ResolveCache\fileCache($this->config['main']['cache_filename']);
if ($this->cache->isDirty()) {
$this->rebuildCache();
}
}
public function searchForFile($filename) {
$path = "";
foreach($this->config['subdirs'] as $key => $value) {
if ($key === "firmware" || $key === "data" || $key === "etc") {
continue;
}
$path = realpath($this->config['main']['base_path'] . DIRECTORY_SEPARATOR . $value['path'] . DIRECTORY_SEPARATOR . $filename);
if (!$path) {
print("path: '" . $this->config['main']['base_path'] . DIRECTORY_SEPARATOR . $value['path'] . DIRECTORY_SEPARATOR . $filename . "' not found\n");
return ResolveResult::FileNotFound;
}
$this->cache->addFile($filename, $path);
return $path;
}
Utils\log_error("File '$filename' does not exist");
return ResolveResult::FileNotFound;
}
public function rebuildCache() {
Utils\log_debug("Rebuilding Cache, standby...");
foreach($this->config['subdirs'] as $key =>$value) {
if ($key === "data" || $key === "etc") {
continue;
}
$path = realpath($this->config['main']['base_path'] . DIRECTORY_SEPARATOR . $value['path'] . DIRECTORY_SEPARATOR);
if (!$path) {
print("path: '" . $this->config['main']['base_path'] . DIRECTORY_SEPARATOR . $value['path'] . "' not found\n");
break;
}
$dir_iterator = new \RecursiveDirectoryIterator($path);
$filter = new \RecursiveCallbackFilterIterator($dir_iterator, function ($current, $key, $iterator) {
// Skip hidden files and directories.
if ($current->getFilename()[0] === '.' || $current->getFilename() == "bak") {
return FALSE;
}
return TRUE;
});
$iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $file) {
if ($file->isFile()) {
if ($value['strip']) {
$this->cache->addFile($file->getFileName(), $file->getPathname());
} else {
$subdir = basename(dirname($file->getPathname()));
$this->cache->addFile($subdir. DIRECTORY_SEPARATOR . $file->getFileName(), $file->getPathname());
}
}
}
}
$this->isDirty = TRUE;
}
public function validateRequest($request) {
/* make sure request does not startwith or contain: "/", "../" or "/./" */
/* make sure request only starts with filename or one of $config[$subdir]['locale'] or $config[$subdir]['wallpaper'] */
/* check uri/url decode */
if (!$request || empty($request)) {
Utils\log_error("Request is empty");
return ResolveResult::EmptyRequest;
}
if (!is_string($request)) {
Utils\log_error("Request is not a string");
return ResolveResult::RequestNotAString;
}
Utils\log_debug($request . ":" . escapeshellarg($request) . ":" . Utils\utf8_urldecode($request) . "\n");
$escaped_request = escapeshellarg(Utils\utf8_urldecode($request));
if ($escaped_request !== "'" . $request . "'") {
Utils\log_error("Request '$request' contains invalid characters");
return ResolveResult::RequestContainsInvalidChar;
}
if (strstr($escaped_request, "..")) {
Utils\log_error("Request '$request' contains '..'");
return ResolveResult::RequestContainsPathWalk;
}
return ResolveResult::Ok;
}
public function resolve($request) /* canthrow */ {
$path = '';
$result = $this->validateRequest($request);
if ($result !== ResolveResult::Ok) {
return $result;
}
if (($path = $this->cache->getPath($request))) {
if (!file_exists($path)) {
$this->cache->removeFile($request);
Utils\log_error("File '$request' does not exist on FS");
return ResolveResult::FileNotFound;
}
return $path;
}
if ($this->searchForFile($request)) {
$path = $this->cache->getPath($request);
}
return $path;
}
/* temporary */
function printCache() {
print_r($this->cache);
}
}
?>