fix: fiabiliser les portées et médias publics
This commit is contained in:
parent
2029849f18
commit
4493357590
11 changed files with 121 additions and 6 deletions
|
|
@ -68,6 +68,7 @@ final class ImageService
|
|||
if (!is_dir($directory) && !mkdir($directory, 0775, true) && !is_dir($directory)) {
|
||||
throw new RuntimeException(t('service.image.directory_failed'));
|
||||
}
|
||||
self::preparePublicDirectory($directory);
|
||||
$prefix = preg_replace('/[^a-z0-9_-]+/i', '_', trim($prefix)) ?: 'photo';
|
||||
$useWebp = $profile !== 'logo';
|
||||
$extension = $useWebp ? 'webp' : $source['extension'];
|
||||
|
|
@ -136,4 +137,25 @@ final class ImageService
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function preparePublicDirectory(string $directory): void
|
||||
{
|
||||
$mediaRoot = dirname(__DIR__, 2) . '/public/media';
|
||||
$normalized = rtrim(str_replace('\\', '/', $directory), '/');
|
||||
$normalizedRoot = rtrim(str_replace('\\', '/', $mediaRoot), '/');
|
||||
if ($normalized !== $normalizedRoot && !str_starts_with($normalized, $normalizedRoot . '/')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@chmod(dirname(__DIR__, 2) . '/data', 0710);
|
||||
$relative = ltrim(substr($normalized, strlen($normalizedRoot)), '/');
|
||||
$current = $normalizedRoot;
|
||||
@chmod($current, 0755);
|
||||
foreach (array_filter(explode('/', $relative), 'strlen') as $segment) {
|
||||
$current .= '/' . $segment;
|
||||
if (is_dir($current)) {
|
||||
@chmod($current, 0755);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,32 @@ final class Migrations
|
|||
}
|
||||
}
|
||||
|
||||
// Deux anciens schémas de l’historique ont circulé : l’un avec
|
||||
// action/field/values, l’autre avec type/label/details. Le code
|
||||
// courant accepte les données des deux et a besoin de leur union.
|
||||
if ($name === '096_animal_history_compatibility.sql') {
|
||||
$columns = array_column(
|
||||
$db->query('PRAGMA table_info(animal_history)')->fetchAll(PDO::FETCH_ASSOC),
|
||||
'name',
|
||||
);
|
||||
$definitions = [
|
||||
'action' => "TEXT NOT NULL DEFAULT 'history'",
|
||||
'field' => 'TEXT',
|
||||
'old_value' => 'TEXT',
|
||||
'new_value' => 'TEXT',
|
||||
'meta' => 'TEXT',
|
||||
'type' => "TEXT NOT NULL DEFAULT 'history'",
|
||||
'label' => "TEXT NOT NULL DEFAULT ''",
|
||||
'details' => 'TEXT',
|
||||
'user_id' => 'INTEGER',
|
||||
];
|
||||
foreach ($definitions as $column => $definition) {
|
||||
if (!in_array($column, $columns, true)) {
|
||||
$db->exec("ALTER TABLE animal_history ADD COLUMN $column $definition");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$relaxesForeignKeys = $name === '093_room_rules_and_care_periods.sql';
|
||||
if ($relaxesForeignKeys) {
|
||||
$db->exec('PRAGMA foreign_keys = OFF');
|
||||
|
|
|
|||
|
|
@ -24,13 +24,12 @@ final class SecurityService
|
|||
public static function hardenRuntimeFiles(): void
|
||||
{
|
||||
$root = dirname(__DIR__, 2);
|
||||
$marker = $root . '/storage/.security-hardened';
|
||||
$marker = $root . '/storage/.security-hardened-v2';
|
||||
if (is_file($marker) && filemtime($marker) > time() - 86400) {
|
||||
return;
|
||||
}
|
||||
foreach (
|
||||
[
|
||||
$root . '/data',
|
||||
$root . '/storage',
|
||||
$root . '/data/private-media',
|
||||
$root . '/data/medical-documents',
|
||||
|
|
@ -45,6 +44,13 @@ final class SecurityService
|
|||
@chmod($dir, 0700);
|
||||
}
|
||||
}
|
||||
// `public/media` may be a symlink into `data` (notably on YunoHost).
|
||||
// Keep the data root traversable without making its private contents
|
||||
// listable, then restore web-safe permissions only below public media.
|
||||
if (is_dir($root . '/data')) {
|
||||
@chmod($root . '/data', 0710);
|
||||
}
|
||||
self::hardenPublicTree($root . '/public/media');
|
||||
foreach (
|
||||
[
|
||||
$root . '/.env',
|
||||
|
|
@ -94,4 +100,19 @@ final class SecurityService
|
|||
@chmod($item->getPathname(), $item->isDir() ? 0700 : 0600);
|
||||
}
|
||||
}
|
||||
|
||||
private static function hardenPublicTree(string $path): void
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
return;
|
||||
}
|
||||
@chmod($path, 0755);
|
||||
$it = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::SELF_FIRST,
|
||||
);
|
||||
foreach ($it as $item) {
|
||||
@chmod($item->getPathname(), $item->isDir() ? 0755 : 0644);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -457,6 +457,7 @@ final class UpdateService
|
|||
{
|
||||
self::clearManagedCode($root);
|
||||
self::copyManagedCode($source, $root);
|
||||
self::normalizePublicCodePermissions($root . '/public');
|
||||
foreach (['data', 'storage', 'public/media'] as $path) {
|
||||
self::ensureDirectory($root . '/' . $path, 0770);
|
||||
}
|
||||
|
|
@ -466,6 +467,7 @@ final class UpdateService
|
|||
{
|
||||
self::clearManagedCode($root);
|
||||
self::copyManagedCode($snapshot, $root);
|
||||
self::normalizePublicCodePermissions($root . '/public');
|
||||
}
|
||||
|
||||
private static function copyManagedCode(string $source, string $target): void
|
||||
|
|
@ -558,6 +560,24 @@ final class UpdateService
|
|||
}
|
||||
}
|
||||
|
||||
private static function normalizePublicCodePermissions(string $publicRoot): void
|
||||
{
|
||||
if (!is_dir($publicRoot)) {
|
||||
return;
|
||||
}
|
||||
@chmod($publicRoot, 0755);
|
||||
$it = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($publicRoot, FilesystemIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::SELF_FIRST,
|
||||
);
|
||||
foreach ($it as $item) {
|
||||
if ($item->isLink()) {
|
||||
continue;
|
||||
}
|
||||
@chmod($item->getPathname(), $item->isDir() ? 0755 : 0644);
|
||||
}
|
||||
}
|
||||
|
||||
private static function removeTree(string $path): void
|
||||
{
|
||||
if (is_link($path) || is_file($path)) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<div class="col-lg-6">
|
||||
<section class="card h-100">
|
||||
<div class="card-body">
|
||||
<span class="badge bg-blue-lt mb-2">1.0.0-rc.23</span>
|
||||
<span class="badge bg-blue-lt mb-2">1.0.0-rc.24</span>
|
||||
<h3>Fiabilité des portées</h3>
|
||||
<p class="text-muted">La création d’une fratrie ne dépend plus d’un ancien traitement de photo et
|
||||
son historique reste compatible avec les bases existantes.</p>
|
||||
|
|
|
|||
Loading…
Reference in a new issue