assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass());
}
+ /**
+ * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
+ * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". This type cannot be instantiated automatically and no service implementing this type is declared.
+ */
+ public function testCreateNonInstanciable()
+ {
+ $container = new ContainerBuilder();
+
+ $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
+ $aDefinition->setAutowired(true);
+
+ $pass = new AutowirePass();
+ $pass->process($container);
+ }
+
public function testResolveParameter()
{
$container = new ContainerBuilder();
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php
index 15de79042ccd9..c56d199b2ffbe 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php
@@ -276,10 +276,12 @@ public function testSetDecoratedServiceOnServiceHasParent()
$container->register('parent', 'stdClass');
$container->setDefinition('child1', new DefinitionDecorator('parent'))
- ->setDecoratedService('foo', 'foo_inner')
+ ->setDecoratedService('foo', 'foo_inner', 5)
;
- $this->assertEquals(array('foo', 'foo_inner', 0), $container->getDefinition('child1')->getDecoratedService());
+ $this->process($container);
+
+ $this->assertEquals(array('foo', 'foo_inner', 5), $container->getDefinition('child1')->getDecoratedService());
}
public function testDecoratedServiceCopiesDeprecatedStatusFromParent()
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
index b0f3535308fdd..5d7b3f0fac1e9 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
@@ -200,7 +200,7 @@ public function testLoadAnonymousServices()
$service = $container->getDefinition($id);
}
$this->assertEquals('BizClass', $service->getClass(), '->load() uses the same configuration as for the anonymous ones');
- $this->assertFalse($service->isPublic());
+ $this->assertTrue($service->isPublic());
// anonymous services are shared when using decoration definitions
$container->compile();
diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json
index 619c9e6304864..db30f65a710a1 100644
--- a/src/Symfony/Component/DependencyInjection/composer.json
+++ b/src/Symfony/Component/DependencyInjection/composer.json
@@ -29,6 +29,7 @@
"suggest": {
"symfony/yaml": "",
"symfony/config": "",
+ "symfony/expression-language": "For using expressions in service container configuration",
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
},
"autoload": {
diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
index e729eeb103715..9b460f55f6ac3 100644
--- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
+++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
@@ -104,6 +104,10 @@ public function getListeners($eventName = null)
*/
public function getListenerPriority($eventName, $listener)
{
+ if (!method_exists($this->dispatcher, 'getListenerPriority')) {
+ return 0;
+ }
+
return $this->dispatcher->getListenerPriority($eventName, $listener);
}
diff --git a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php
index 2dd8292a1b3e6..dd54e73b34f24 100644
--- a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php
+++ b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php
@@ -73,6 +73,16 @@ public function testGetListenerPriority()
$this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0]));
}
+ public function testGetListenerPriorityReturnsZeroWhenWrappedMethodDoesNotExist()
+ {
+ $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+ $traceableEventDispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
+ $traceableEventDispatcher->addListener('foo', function () {}, 123);
+ $listeners = $traceableEventDispatcher->getListeners('foo');
+
+ $this->assertSame(0, $traceableEventDispatcher->getListenerPriority('foo', $listeners[0]));
+ }
+
public function testAddRemoveSubscriber()
{
$dispatcher = new EventDispatcher();
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index cfb6781f394da..a95bd97ee3a21 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -59,11 +59,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface
protected $startTime;
protected $loadClassCache;
- const VERSION = '2.8.5';
- const VERSION_ID = 20805;
+ const VERSION = '2.8.6';
+ const VERSION_ID = 20806;
const MAJOR_VERSION = 2;
const MINOR_VERSION = 8;
- const RELEASE_VERSION = 5;
+ const RELEASE_VERSION = 6;
const EXTRA_VERSION = '';
const END_OF_MAINTENANCE = '11/2018';
diff --git a/src/Symfony/Component/HttpKernel/KernelEvents.php b/src/Symfony/Component/HttpKernel/KernelEvents.php
index 8768979da6bd4..abbbfcc0048b9 100644
--- a/src/Symfony/Component/HttpKernel/KernelEvents.php
+++ b/src/Symfony/Component/HttpKernel/KernelEvents.php
@@ -108,6 +108,10 @@ final class KernelEvents
*
* This event allows you to reset the global and environmental state of
* the application, when it was changed during the request.
+ * The event listener method receives a
+ * Symfony\Component\HttpKernel\Event\FinishRequestEvent instance.
+ *
+ * @Event
*
* @var string
*/
diff --git a/src/Symfony/Component/OptionsResolver/README.md b/src/Symfony/Component/OptionsResolver/README.md
index 5768f68e7ff7d..245e69b548d6d 100644
--- a/src/Symfony/Component/OptionsResolver/README.md
+++ b/src/Symfony/Component/OptionsResolver/README.md
@@ -1,7 +1,7 @@
OptionsResolver Component
=========================
-The OptionsResolver component is `array_replace on steroids. It allows you to
+The OptionsResolver component is `array_replace` on steroids. It allows you to
create an options system with required options, defaults, validation (type,
value), normalization and more.
diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
index 9b7262d237595..63454a5b45319 100644
--- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
+++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
@@ -40,7 +40,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
/**
* @internal
*
- * @var array[]
+ * @var string[]
*/
public static $arrayMutatorPrefixes = array('add', 'remove');
diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php
index d139e40857131..4a6b742ea0a9c 100644
--- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php
+++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php
@@ -75,11 +75,6 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
'%7C' => '|',
);
- /**
- * @var string This regexp matches all characters that are not or should not be encoded by rawurlencode (see list in array above).
- */
- private $urlEncodingSkipRegexp = '#[^-.~a-zA-Z0-9_/@:;,=+!*|]#';
-
/**
* Constructor.
*
@@ -201,21 +196,19 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa
if ('' === $url) {
$url = '/';
- } elseif (preg_match($this->urlEncodingSkipRegexp, $url)) {
- // the context base URL is already encoded (see Symfony\Component\HttpFoundation\Request)
- $url = strtr(rawurlencode($url), $this->decodedChars);
}
+ // the contexts base URL is already encoded (see Symfony\Component\HttpFoundation\Request)
+ $url = strtr(rawurlencode($url), $this->decodedChars);
+
// the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
// so we need to encode them as they are not used for this purpose here
// otherwise we would generate a URI that, when followed by a user agent (e.g. browser), does not match this route
- if (false !== strpos($url, '/.')) {
- $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/'));
- if ('/..' === substr($url, -3)) {
- $url = substr($url, 0, -2).'%2E%2E';
- } elseif ('/.' === substr($url, -2)) {
- $url = substr($url, 0, -1).'%2E';
- }
+ $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/'));
+ if ('/..' === substr($url, -3)) {
+ $url = substr($url, 0, -2).'%2E%2E';
+ } elseif ('/.' === substr($url, -2)) {
+ $url = substr($url, 0, -1).'%2E';
}
$schemeAuthority = '';
@@ -292,7 +285,7 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa
if ($extra && $query = http_build_query($extra, '', '&')) {
// "/" and "?" can be left decoded for better user experience, see
// http://tools.ietf.org/html/rfc3986#section-3.4
- $url .= '?'.(false === strpos($query, '%2F') ? $query : strtr($query, array('%2F' => '/')));
+ $url .= '?'.strtr($query, array('%2F' => '/'));
}
return $url;
diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php
index adc42ef3b38f5..e887f99af7963 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Provider/LdapBindAuthenticationProvider.php
@@ -73,6 +73,10 @@ protected function checkAuthentication(UserInterface $user, UsernamePasswordToke
$username = $token->getUsername();
$password = $token->getCredentials();
+ if ('' === $password) {
+ throw new BadCredentialsException('The presented password must not be empty.');
+ }
+
try {
$username = $this->ldap->escape($username, '', LDAP_ESCAPE_DN);
$dn = str_replace('{username}', $username, $this->dnString);
diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php
index 22fc611b2a16b..71dea3230783e 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php
@@ -26,7 +26,7 @@ class AnonymousToken extends AbstractToken
* Constructor.
*
* @param string $secret A secret used to make sure the token is created by the app and not by a malicious client
- * @param string $user The user
+ * @param string|object $user The user can be a UserInterface instance, or an object implementing a __toString method or the username as a regular string.
* @param RoleInterface[] $roles An array of roles
*/
public function __construct($secret, $user, array $roles = array())
diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php
index 1798203690455..5a3fc95327c08 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php
@@ -26,7 +26,7 @@ class PreAuthenticatedToken extends AbstractToken
/**
* Constructor.
*
- * @param string|object $user The user
+ * @param string|object $user The user can be a UserInterface instance, or an object implementing a __toString method or the username as a regular string.
* @param mixed $credentials The user credentials
* @param string $providerKey The provider key
* @param RoleInterface[]|string[] $roles An array of roles
diff --git a/src/Symfony/Component/Security/Core/AuthenticationEvents.php b/src/Symfony/Component/Security/Core/AuthenticationEvents.php
index 90b714267466c..13bce30768908 100644
--- a/src/Symfony/Component/Security/Core/AuthenticationEvents.php
+++ b/src/Symfony/Component/Security/Core/AuthenticationEvents.php
@@ -20,6 +20,8 @@ final class AuthenticationEvents
* The event listener method receives a
* Symfony\Component\Security\Core\Event\AuthenticationEvent instance.
*
+ * @Event
+ *
* @var string
*/
const AUTHENTICATION_SUCCESS = 'security.authentication.success';
@@ -32,6 +34,8 @@ final class AuthenticationEvents
* Symfony\Component\Security\Core\Event\AuthenticationFailureEvent
* instance.
*
+ * @Event
+ *
* @var string
*/
const AUTHENTICATION_FAILURE = 'security.authentication.failure';
diff --git a/src/Symfony/Component/Security/Core/Security.php b/src/Symfony/Component/Security/Core/Security.php
index 14d32f81482e5..84cc77dcf7f32 100644
--- a/src/Symfony/Component/Security/Core/Security.php
+++ b/src/Symfony/Component/Security/Core/Security.php
@@ -21,4 +21,5 @@ final class Security
const ACCESS_DENIED_ERROR = '_security.403_error';
const AUTHENTICATION_ERROR = '_security.last_error';
const LAST_USERNAME = '_security.last_username';
+ const MAX_USERNAME_LENGTH = 4096;
}
diff --git a/src/Symfony/Component/Security/Core/SecurityContextInterface.php b/src/Symfony/Component/Security/Core/SecurityContextInterface.php
index 2a06ca426a487..73edd2383573b 100644
--- a/src/Symfony/Component/Security/Core/SecurityContextInterface.php
+++ b/src/Symfony/Component/Security/Core/SecurityContextInterface.php
@@ -26,4 +26,5 @@ interface SecurityContextInterface extends TokenStorageInterface, AuthorizationC
const ACCESS_DENIED_ERROR = Security::ACCESS_DENIED_ERROR;
const AUTHENTICATION_ERROR = Security::AUTHENTICATION_ERROR;
const LAST_USERNAME = Security::LAST_USERNAME;
+ const MAX_USERNAME_LENGTH = Security::MAX_USERNAME_LENGTH;
}
diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php
index 844bceff019cb..fbb4d733a93c4 100644
--- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php
+++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/LdapBindAuthenticationProviderTest.php
@@ -21,6 +21,23 @@
*/
class LdapBindAuthenticationProviderTest extends \PHPUnit_Framework_TestCase
{
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
+ * @expectedExceptionMessage The presented password must not be empty.
+ */
+ public function testEmptyPasswordShouldThrowAnException()
+ {
+ $userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
+ $ldap = $this->getMock('Symfony\Component\Ldap\LdapClientInterface');
+ $userChecker = $this->getMock('Symfony\Component\Security\Core\User\UserCheckerInterface');
+
+ $provider = new LdapBindAuthenticationProvider($userProvider, $userChecker, 'key', $ldap);
+ $reflection = new \ReflectionMethod($provider, 'checkAuthentication');
+ $reflection->setAccessible(true);
+
+ $reflection->invoke($provider, new User('foo', null), new UsernamePasswordToken('foo', '', 'key'));
+ }
+
/**
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
* @expectedExceptionMessage The presented password is invalid.
@@ -40,7 +57,7 @@ public function testBindFailureShouldThrowAnException()
$reflection = new \ReflectionMethod($provider, 'checkAuthentication');
$reflection->setAccessible(true);
- $reflection->invoke($provider, new User('foo', null), new UsernamePasswordToken('foo', '', 'key'));
+ $reflection->invoke($provider, new User('foo', null), new UsernamePasswordToken('foo', 'bar', 'key'));
}
public function testRetrieveUser()
diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php
index 436376360be3a..331d018471de8 100644
--- a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php
+++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php
@@ -24,6 +24,7 @@
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\Security\Http\ParameterBagUtils;
@@ -127,6 +128,10 @@ protected function attemptAuthentication(Request $request)
$password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']);
}
+ if (strlen($username) > Security::MAX_USERNAME_LENGTH) {
+ throw new BadCredentialsException('Invalid username.');
+ }
+
$request->getSession()->set(Security::LAST_USERNAME, $username);
$token = $this->simpleAuthenticator->createToken($request, $username, $password, $this->providerKey);
diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
index 24c3ca6509c26..866d0c32d9c8b 100644
--- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
+++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
@@ -25,6 +25,7 @@
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
@@ -102,6 +103,10 @@ protected function attemptAuthentication(Request $request)
$password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']);
}
+ if (strlen($username) > Security::MAX_USERNAME_LENGTH) {
+ throw new BadCredentialsException('Invalid username.');
+ }
+
$request->getSession()->set(Security::LAST_USERNAME, $username);
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
diff --git a/src/Symfony/Component/Security/Tests/Http/Firewall/UsernamePasswordFormAuthenticationListenerTest.php b/src/Symfony/Component/Security/Tests/Http/Firewall/UsernamePasswordFormAuthenticationListenerTest.php
new file mode 100644
index 0000000000000..b7c6ab9db5752
--- /dev/null
+++ b/src/Symfony/Component/Security/Tests/Http/Firewall/UsernamePasswordFormAuthenticationListenerTest.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Tests\Http\Firewall;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener;
+use Symfony\Component\Security\Core\SecurityContextInterface;
+
+class UsernamePasswordFormAuthenticationListenerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getUsernameForLength
+ */
+ public function testHandleWhenUsernameLength($username, $ok)
+ {
+ $request = Request::create('/login_check', 'POST', array('_username' => $username));
+ $request->setSession($this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
+
+ $httpUtils = $this->getMock('Symfony\Component\Security\Http\HttpUtils');
+ $httpUtils
+ ->expects($this->any())
+ ->method('checkRequestPath')
+ ->will($this->returnValue(true))
+ ;
+
+ $failureHandler = $this->getMock('Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface');
+ $failureHandler
+ ->expects($ok ? $this->never() : $this->once())
+ ->method('onAuthenticationFailure')
+ ->will($this->returnValue(new Response()))
+ ;
+
+ $authenticationManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager')->disableOriginalConstructor()->getMock();
+ $authenticationManager
+ ->expects($ok ? $this->once() : $this->never())
+ ->method('authenticate')
+ ->will($this->returnValue(new Response()))
+ ;
+
+ $listener = new UsernamePasswordFormAuthenticationListener(
+ $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'),
+ $authenticationManager,
+ $this->getMock('Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface'),
+ $httpUtils,
+ 'TheProviderKey',
+ $this->getMock('Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface'),
+ $failureHandler,
+ array('require_previous_session' => false)
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function getUsernameForLength()
+ {
+ return array(
+ array(str_repeat('x', SecurityContextInterface::MAX_USERNAME_LENGTH + 1), false),
+ array(str_repeat('x', SecurityContextInterface::MAX_USERNAME_LENGTH - 1), true),
+ );
+ }
+}
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy