fix: load markdown in direct.php, allow video-channels, guard modals
This commit is contained in:
@@ -141,6 +141,18 @@ assertTrue(
|
||||
isValidApiEndpoint('accounts/annu_kute_ced/videos'),
|
||||
'isValidApiEndpoint accepte les vidéos d\'un compte'
|
||||
);
|
||||
assertTrue(
|
||||
isValidApiEndpoint('video-channels/annu_kute_ced/videos'),
|
||||
'isValidApiEndpoint accepte les vidéos d\'une chaîne'
|
||||
);
|
||||
assertFalse(
|
||||
isValidApiEndpoint('video-channels/annu_kute_ced'),
|
||||
'isValidApiEndpoint refuse une chaîne sans sous-chemin /videos'
|
||||
);
|
||||
assertFalse(
|
||||
isValidApiEndpoint('video-channels'),
|
||||
'isValidApiEndpoint refuse "video-channels" seul'
|
||||
);
|
||||
assertFalse(isValidApiEndpoint('../config'), 'isValidApiEndpoint refuse le path traversal');
|
||||
assertFalse(isValidApiEndpoint('videos/../x'), 'isValidApiEndpoint refuse ".." dans le chemin');
|
||||
assertFalse(isValidApiEndpoint('videos//categories'), 'isValidApiEndpoint refuse un double slash');
|
||||
@@ -155,3 +167,91 @@ $nonce = getCspNonce();
|
||||
assertTrue(is_string($nonce) && $nonce !== '', 'getCspNonce retourne une chaîne non vide');
|
||||
assertEquals(16, strlen(base64_decode($nonce, true)), 'getCspNonce est un base64 de 16 octets aléatoires');
|
||||
assertEquals($nonce, getCspNonce(), 'getCspNonce retourne le même nonce durant toute la requête');
|
||||
|
||||
// --- getCsrfSecret ------------------------------------------------------------
|
||||
|
||||
assertEquals(
|
||||
CSRF_SECRET,
|
||||
getCsrfSecret(),
|
||||
'getCsrfSecret retourne CSRF_SECRET quand il est configuré'
|
||||
);
|
||||
|
||||
// Repli éphémère : impossible à tester dans ce processus (CSRF_SECRET est déjà
|
||||
// défini par le bootstrap), on passe par un sous-processus PHP isolé dont la
|
||||
// sortie d'erreur est redirigée vers stdout pour capter l'avertissement.
|
||||
$securityFile = dirname(__DIR__, 2) . '/includes/security.php';
|
||||
$snippet = <<<'PHP'
|
||||
require $argv[1];
|
||||
define('CSRF_SECRET', CSRF_SECRET_PLACEHOLDER);
|
||||
$s1 = getCsrfSecret();
|
||||
$s2 = getCsrfSecret();
|
||||
echo 'len=' . strlen($s1) . "\n";
|
||||
echo 'same=' . ($s1 === $s2 ? 'yes' : 'no') . "\n";
|
||||
echo 'placeholder=' . ($s1 === CSRF_SECRET ? 'yes' : 'no') . "\n";
|
||||
$token = generateCSRFToken();
|
||||
echo 'token=' . (validateCSRFToken($token) ? 'valid' : 'invalid') . "\n";
|
||||
PHP;
|
||||
|
||||
$cmd = escapeshellarg(PHP_BINARY)
|
||||
. ' -d log_errors=1 -d error_log=/dev/stdout -r '
|
||||
. escapeshellarg($snippet)
|
||||
. ' ' . escapeshellarg($securityFile);
|
||||
$fallbackOutput = function_exists('shell_exec') ? shell_exec($cmd) : null;
|
||||
|
||||
if ($fallbackOutput === null) {
|
||||
test_record(false, 'getCsrfSecret : sous-processus de test du repli éphémère (shell_exec indisponible)');
|
||||
} else {
|
||||
assertContains(
|
||||
'SECURITY CRITICAL',
|
||||
$fallbackOutput,
|
||||
'getCsrfSecret enregistre un avertissement critique avec la valeur par défaut'
|
||||
);
|
||||
assertContains(
|
||||
'CSRF_SECRET',
|
||||
$fallbackOutput,
|
||||
'l\'avertissement critique mentionne CSRF_SECRET'
|
||||
);
|
||||
assertContains(
|
||||
'len=64',
|
||||
$fallbackOutput,
|
||||
'le secret éphémère fait 64 caractères hexadécimaux (32 octets)'
|
||||
);
|
||||
assertContains(
|
||||
'same=yes',
|
||||
$fallbackOutput,
|
||||
'le secret éphémère est stable durant tout le processus'
|
||||
);
|
||||
assertContains(
|
||||
'placeholder=no',
|
||||
$fallbackOutput,
|
||||
'le secret éphémère diffère de la valeur par défaut'
|
||||
);
|
||||
assertContains(
|
||||
'token=valid',
|
||||
$fallbackOutput,
|
||||
'un token signé avec le secret éphémère est validé dans le même processus'
|
||||
);
|
||||
}
|
||||
|
||||
// --- isValidRemoteUrl (includes/security.php) ---------------------------------
|
||||
|
||||
assertTrue(isValidRemoteUrl('https://peertube.example.com'), 'isValidRemoteUrl accepte une URL HTTPS publique');
|
||||
assertTrue(isValidRemoteUrl('https://kute.o-k-i.net'), 'isValidRemoteUrl accepte une instance Castopod publique');
|
||||
assertTrue(isValidRemoteUrl('https://mizik.o-k-i.net'), 'isValidRemoteUrl accepte une instance Funkwhale publique');
|
||||
assertTrue(isValidRemoteUrl('http://castopod.example.com'), 'isValidRemoteUrl accepte HTTP (développement)');
|
||||
assertFalse(isValidRemoteUrl('ftp://kute.o-k-i.net'), 'isValidRemoteUrl refuse un schéma non HTTP(S)');
|
||||
assertFalse(isValidRemoteUrl('pas-une-url'), 'isValidRemoteUrl refuse une chaîne mal formée');
|
||||
assertFalse(isValidRemoteUrl(''), 'isValidRemoteUrl refuse une chaîne vide');
|
||||
assertFalse(isValidRemoteUrl('https://localhost'), 'isValidRemoteUrl refuse localhost');
|
||||
assertFalse(isValidRemoteUrl('http://127.0.0.1'), 'isValidRemoteUrl refuse 127.0.0.1');
|
||||
assertFalse(isValidRemoteUrl('http://192.168.1.1'), 'isValidRemoteUrl refuse une IP privée (192.168.x)');
|
||||
assertFalse(isValidRemoteUrl('http://10.0.0.5'), 'isValidRemoteUrl refuse une IP privée (10.x)');
|
||||
assertFalse(isValidRemoteUrl('http://172.16.0.1'), 'isValidRemoteUrl refuse une IP privée (172.16.x)');
|
||||
assertFalse(
|
||||
isValidRemoteUrl('http://169.254.169.254/latest/meta-data'),
|
||||
'isValidRemoteUrl refuse l\'IP de métadonnées cloud (link-local)'
|
||||
);
|
||||
assertFalse(
|
||||
isValidRemoteUrl('https://metadata.google.internal'),
|
||||
'isValidRemoteUrl refuse metadata.google.internal'
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user