fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled
Some checks failed
Deploy Application / deploy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Framework\DateTime\SystemClock;
|
||||
use App\Framework\Http\Session\FileSessionStorage;
|
||||
use App\Framework\Http\Session\FormIdGenerator;
|
||||
use App\Framework\Http\Session\Session;
|
||||
use App\Framework\Http\Session\SessionId;
|
||||
use App\Framework\Http\Session\SessionIdGenerator;
|
||||
use App\Framework\Http\Session\SessionManager;
|
||||
use App\Framework\Random\SecureRandomGenerator;
|
||||
use App\Framework\Security\CsrfTokenGenerator;
|
||||
use App\Framework\View\Response\FormDataResponseProcessor;
|
||||
use App\Framework\Http\Cookies\SessionCookieConfig;
|
||||
|
||||
beforeEach(function () {
|
||||
$this->tempDir = sys_get_temp_dir() . '/php_sessions_test_' . uniqid();
|
||||
mkdir($this->tempDir, 0700, true);
|
||||
|
||||
$this->clock = new SystemClock();
|
||||
$this->storage = new FileSessionStorage($this->tempDir, $this->clock);
|
||||
$this->sessionIdGenerator = new SessionIdGenerator(new SecureRandomGenerator());
|
||||
$this->csrfTokenGenerator = new CsrfTokenGenerator(new SecureRandomGenerator());
|
||||
$this->formIdGenerator = new FormIdGenerator();
|
||||
|
||||
$this->cookieConfig = new SessionCookieConfig(
|
||||
name: 'test_session',
|
||||
lifetime: 3600,
|
||||
path: '/',
|
||||
domain: null,
|
||||
secure: false,
|
||||
httpOnly: true,
|
||||
sameSite: \App\Framework\Http\Cookies\SameSite::LAX
|
||||
);
|
||||
|
||||
$this->sessionManager = new SessionManager(
|
||||
generator: $this->sessionIdGenerator,
|
||||
responseManipulator: Mockery::mock(\App\Framework\Http\ResponseManipulator::class),
|
||||
clock: $this->clock,
|
||||
csrfTokenGenerator: $this->csrfTokenGenerator,
|
||||
storage: $this->storage,
|
||||
cookieConfig: $this->cookieConfig
|
||||
);
|
||||
|
||||
$this->sessionId = $this->sessionIdGenerator->generate();
|
||||
$this->session = Session::fromArray($this->sessionId, $this->clock, $this->csrfTokenGenerator, []);
|
||||
|
||||
$this->processor = new FormDataResponseProcessor(
|
||||
$this->formIdGenerator,
|
||||
$this->sessionManager
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
if (isset($this->tempDir) && is_dir($this->tempDir)) {
|
||||
array_map('unlink', glob($this->tempDir . '/*'));
|
||||
rmdir($this->tempDir);
|
||||
}
|
||||
});
|
||||
|
||||
it('processes form HTML and replaces token placeholder', function () {
|
||||
$formId = $this->formIdGenerator->generateFormId('/test', 'post');
|
||||
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Test</title></head>
|
||||
<body>
|
||||
<form method="post" action="/test">
|
||||
<input type="hidden" name="_form_id" value="{$formId}">
|
||||
<input type="hidden" name="_token" value="___TOKEN_{$formId}___">
|
||||
<input type="text" name="email" value="">
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
$processed = $this->processor->process($html, $this->session);
|
||||
|
||||
// Token should be replaced
|
||||
expect($processed)->not->toContain("___TOKEN_{$formId}___");
|
||||
|
||||
// Should contain a valid token
|
||||
preg_match('/name="_token"[^>]*value="([^"]+)"/', $processed, $matches);
|
||||
expect($matches)->toHaveCount(2);
|
||||
|
||||
$token = $matches[1];
|
||||
expect(strlen($token))->toBe(64);
|
||||
expect(ctype_xdigit($token))->toBeTrue();
|
||||
|
||||
// Token should be valid in session
|
||||
$tokenObj = \App\Framework\Security\CsrfToken::fromString($token);
|
||||
$result = $this->session->csrf->validateTokenWithDebug($formId, $tokenObj);
|
||||
expect($result['valid'])->toBeTrue();
|
||||
});
|
||||
|
||||
it('processes multiple forms with different form IDs', function () {
|
||||
$formId1 = $this->formIdGenerator->generateFormId('/form1', 'post');
|
||||
$formId2 = $this->formIdGenerator->generateFormId('/form2', 'post');
|
||||
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<form method="post" action="/form1">
|
||||
<input type="hidden" name="_form_id" value="{$formId1}">
|
||||
<input type="hidden" name="_token" value="___TOKEN_{$formId1}___">
|
||||
</form>
|
||||
<form method="post" action="/form2">
|
||||
<input type="hidden" name="_form_id" value="{$formId2}">
|
||||
<input type="hidden" name="_token" value="___TOKEN_{$formId2}___">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
$processed = $this->processor->process($html, $this->session);
|
||||
|
||||
// Both tokens should be replaced
|
||||
expect($processed)->not->toContain("___TOKEN_{$formId1}___");
|
||||
expect($processed)->not->toContain("___TOKEN_{$formId2}___");
|
||||
|
||||
// Extract tokens
|
||||
preg_match_all('/name="_token"[^>]*value="([^"]+)"/', $processed, $matches);
|
||||
expect($matches[1])->toHaveCount(2);
|
||||
|
||||
$token1 = $matches[1][0];
|
||||
$token2 = $matches[1][1];
|
||||
|
||||
// Tokens should be different
|
||||
expect($token1)->not->toBe($token2);
|
||||
|
||||
// Both should be valid
|
||||
expect(strlen($token1))->toBe(64);
|
||||
expect(strlen($token2))->toBe(64);
|
||||
});
|
||||
|
||||
it('handles malformed HTML gracefully', function () {
|
||||
$formId = $this->formIdGenerator->generateFormId('/test', 'post');
|
||||
|
||||
// HTML with unclosed tags
|
||||
$html = <<<HTML
|
||||
<form method="post" action="/test">
|
||||
<input type="hidden" name="_form_id" value="{$formId}">
|
||||
<input type="hidden" name="_token" value="___TOKEN_{$formId}___">
|
||||
<div>
|
||||
<unclosed-tag>
|
||||
</form>
|
||||
HTML;
|
||||
|
||||
// Should not throw exception
|
||||
$processed = $this->processor->process($html, $this->session);
|
||||
|
||||
// Should still replace token (via regex fallback)
|
||||
expect($processed)->not->toContain("___TOKEN_{$formId}___");
|
||||
});
|
||||
|
||||
it('preserves HTML structure after processing', function () {
|
||||
$formId = $this->formIdGenerator->generateFormId('/test', 'post');
|
||||
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test Form</h1>
|
||||
<form method="post" action="/test">
|
||||
<input type="hidden" name="_form_id" value="{$formId}">
|
||||
<input type="hidden" name="_token" value="___TOKEN_{$formId}___">
|
||||
<label>Email:</label>
|
||||
<input type="email" name="email">
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
$processed = $this->processor->process($html, $this->session);
|
||||
|
||||
// Should preserve structure
|
||||
expect($processed)->toContain('<!DOCTYPE html>');
|
||||
expect($processed)->toContain('<html>');
|
||||
expect($processed)->toContain('<head>');
|
||||
expect($processed)->toContain('<title>Test Page</title>');
|
||||
expect($processed)->toContain('<h1>Test Form</h1>');
|
||||
expect($processed)->toContain('<label>Email:</label>');
|
||||
expect($processed)->toContain('<button type="submit">Submit</button>');
|
||||
|
||||
// Token should be replaced
|
||||
expect($processed)->not->toContain("___TOKEN_{$formId}___");
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user