feat(ecosystem): full Grade 10 curriculum sync, real device fingerprinting, teacher video dashboard, and official textbook assets
This commit is contained in:
@@ -43,11 +43,39 @@ final class PublishedContentService
|
||||
return null;
|
||||
}
|
||||
$root = realpath(self::STORAGE_ROOT);
|
||||
$path = $root ? realpath($root . '/' . ltrim((string)$asset['storage_key'], '/')) : false;
|
||||
$prefix = $root ? rtrim($root, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : '';
|
||||
if (!$path || !$prefix || !str_starts_with($path, $prefix) || !is_file($path)) {
|
||||
if (!$root) {
|
||||
return null;
|
||||
}
|
||||
return $path;
|
||||
$storageKey = ltrim((string)($asset['storage_key'] ?? ''), '/');
|
||||
if ($storageKey === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$candidates = [
|
||||
$root . '/' . $storageKey,
|
||||
$root . '/_incoming/' . $storageKey,
|
||||
dirname($root) . '/' . $storageKey,
|
||||
dirname($root, 2) . '/' . $storageKey,
|
||||
];
|
||||
|
||||
if (preg_match('#staged/grade_10/[^/]+/(.+)#', $storageKey, $matches)) {
|
||||
$inner = $matches[1];
|
||||
$candidates[] = $root . '/' . $inner;
|
||||
$candidates[] = $root . '/_incoming/' . $inner;
|
||||
}
|
||||
|
||||
$prefix = rtrim($root, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
$projectRoot = realpath(dirname(__DIR__, 2)) ?: '';
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
$real = realpath($candidate);
|
||||
if ($real && is_file($real)) {
|
||||
// Ensure candidate is strictly within the project root to prevent traversal
|
||||
if ($projectRoot !== '' && str_starts_with($real, $projectRoot)) {
|
||||
return $real;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user