diff --git a/lib/KD2/WebDAV/NextCloud.php b/lib/KD2/WebDAV/NextCloud.php index 3aaae7e..41cc769 100644 --- a/lib/KD2/WebDAV/NextCloud.php +++ b/lib/KD2/WebDAV/NextCloud.php @@ -501,7 +501,8 @@ abstract class NextCloud { $uri = trim($uri, '/'); $expire = intval((time() - strtotime('2022-09-01'))/3600) + 8; // 8 hours - $hash = $expire . ':' . hash_hmac('sha1', $user . "\0" . $expire . "\0" . $uri, $this->getDirectDownloadSecret($uri, $user)); + $hash = Server::hmac([$user, $expire, $uri], $this->getDirectDownloadSecret($uri, $user)); + $hash = $expire . ':' . $hash; $uri = rawurlencode($uri); $uri = str_replace('%2F', '/', $uri); @@ -577,7 +578,7 @@ abstract class NextCloud throw new Exception('Link has expired', 401); } - $verify = hash_hmac('sha1', $user . "\0" . $expire . "\0" . $uri, $this->getDirectDownloadSecret($uri, $user)); + $verify = Server::hmac([$user, $expire, $uri], $this->getDirectDownloadSecret($uri, $user)); // Check if the provided hash is correct if (!hash_equals($verify, $hash)) { diff --git a/lib/KD2/WebDAV/Server.php b/lib/KD2/WebDAV/Server.php index f519cce..199621b 100644 --- a/lib/KD2/WebDAV/Server.php +++ b/lib/KD2/WebDAV/Server.php @@ -631,6 +631,10 @@ class Server $body = file_get_contents('php://input'); + if (false !== strpos($body, 'log('Requested depth: %s', $depth); // We don't really care about having a correct XML string, @@ -822,6 +826,10 @@ class Server static public function parsePropPatch(string $body): array { + if (false !== strpos($body, '%s', htmlspecialchars($e->getMessage(), ENT_XML1)); } + + /** + * Utility function to create HMAC hash of data, useful for NextCloud and WOPI + */ + static public function hmac(array $data, string $key = '') + { + // Protect against length attacks by pre-hashing data + $data = array_map('sha1', $data); + $data = implode(':', $details); + + return hash_hmac('sha1', $data, sha1($key)); + } } diff --git a/lib/KD2/WebDAV/WOPI.php b/lib/KD2/WebDAV/WOPI.php index 57206a5..05d30d1 100644 --- a/lib/KD2/WebDAV/WOPI.php +++ b/lib/KD2/WebDAV/WOPI.php @@ -190,7 +190,11 @@ class WOPI } } - $xml = simplexml_load_string($r); + if (false !== strpos($r, 'login . $user->password); + return WebDAV::hmac([$uri, $user->login, $user->password]); } protected function cleanChunks(): void diff --git a/lib/KaraDAV/Storage.php b/lib/KaraDAV/Storage.php index 07965be..a88a1ed 100644 --- a/lib/KaraDAV/Storage.php +++ b/lib/KaraDAV/Storage.php @@ -481,8 +481,8 @@ class Storage extends AbstractStorage $ttl = time()+(3600*10); // Use the user password as a server secret - $hash = hash_hmac('sha1', $ttl . "\0" . $uri, $user->password); - $data = sprintf('%s_%s_%s', $hash, $ttl, $user->login); + $check = WebDAV::hash(compact('ttl', 'uri'), $user->password); + $data = sprintf('%s_%s_%s', $check, $ttl, $user->login); return [ WOPI::PROP_TOKEN => WOPI::base64_encode_url_safe($data), @@ -509,7 +509,7 @@ class Storage extends AbstractStorage $user = $this->users->current(); - $check = hash_hmac('sha1', $ttl . "\0" . $uri, $user->password); + $check = WebDAV::hash(compact('ttl', 'uri'), $user->password); if (!hash_equals($check, $hash)) { return null; diff --git a/lib/KaraDAV/WebDAV.php b/lib/KaraDAV/WebDAV.php index b6b5413..c04293c 100644 --- a/lib/KaraDAV/WebDAV.php +++ b/lib/KaraDAV/WebDAV.php @@ -37,4 +37,13 @@ class WebDAV extends WebDAV_Server { http_log('DAV: ' . $message, ...$params); } + + /** + * Utility function to create HMAC hash of data, useful for NextCloud and WOPI + */ + static public function hmac(array $data, string $key = '') + { + $key = SECRET_KEY . sha1($key); + return parent::hmac($data, $key); + } } diff --git a/www/_inc.php b/www/_inc.php index 2075219..9fbdce8 100644 --- a/www/_inc.php +++ b/www/_inc.php @@ -12,11 +12,31 @@ spl_autoload_register(function ($class) { ErrorManager::enable(ErrorManager::DEVELOPMENT); ErrorManager::setLogFile(__DIR__ . '/../error.log'); -if (!file_exists(__DIR__ . '/../config.local.php')) { +$cfg_file = __DIR__ . '/../config.local.php'; + +if (!file_exists($cfg_file)) { die('This server is not configured yet. Please copy config.dist.php to config.local.php and edit it.'); } -require __DIR__ . '/../config.local.php'; +require $cfg_file; + +// Create random secret key +if (!defined('KaraDAV\SECRET_KEY')) { + $cfg = file_get_contents($cfg_file); + + if (false == strpos($cfg, 'SECRET_KEY')) { + $secret = base64_encode(random_bytes(16)); + define('KaraDAV\SECRET_KEY', $secret); + + $c = sprintf("\n\n// Randomly generated secret key, please change only if necessary\nconst SECRET_KEY = %s;\n\n", + var_export($secret, true)); + + $cfg = preg_replace('/\?>\s*$|$/', $c, $cfg, 1); + + file_put_contents($cfg_file, $cfg); + unset($secret, $cfg_file, $cfg); + } +} // Init database if (!file_exists(DB_FILE)) {