[ Index ]

PHP Cross Reference of YOURLS

title

Body

[close]

/tests/tests/auth/ -> LoginCookieTest.php (source)

   1  <?php
   2  /**
   3   * Login tests - via Cookies - and cookie functions tests
   4   */
   5  #[\PHPUnit\Framework\Attributes\Group('auth')]
   6  #[\PHPUnit\Framework\Attributes\Group('login')]
   7  #[\PHPUnit\Framework\Attributes\Group('cookies')]
   8  class LoginCookieTest extends PHPUnit\Framework\TestCase {
   9  
  10      protected $cookie;
  11      protected $request;
  12      protected $backup_yourls_actions;
  13  
  14      protected $added_filters = [];
  15  
  16      protected function setUp(): void {
  17          $this->cookie = $_COOKIE;
  18          $this->request = $_REQUEST;
  19          global $yourls_actions;
  20          $this->backup_yourls_actions = $yourls_actions;
  21      }
  22  
  23      protected function tearDown(): void {
  24          $_COOKIE = $this->cookie;
  25          $_REQUEST = $this->request;
  26          global $yourls_actions;
  27          $yourls_actions = $this->backup_yourls_actions;
  28  
  29          foreach ( $this->added_filters as $filter ) {
  30              yourls_remove_filter( $filter[0], $filter[1] );
  31          }
  32          $this->added_filters = [];
  33      }
  34  
  35      /**
  36       * Add a filter and register it for automatic removal in tearDown()
  37       */
  38      protected function add_filter( string $hook, $callback ): void {
  39          yourls_add_filter( $hook, $callback );
  40          $this->added_filters[] = [ $hook, $callback ];
  41      }
  42  
  43      /**
  44       * Add an action and register it for automatic removal in tearDown()
  45       * (actions are stored alongside filters, so yourls_remove_filter() works)
  46       */
  47      protected function add_action( string $hook, $callback ): void {
  48          yourls_add_action( $hook, $callback );
  49          $this->added_filters[] = [ $hook, $callback ];
  50      }
  51  
  52      public static function setUpBeforeClass(): void {
  53          yourls_add_filter( 'is_API', 'yourls_return_false' );
  54      }
  55  
  56      public static function tearDownAfterClass(): void {
  57          yourls_remove_filter( 'is_API', 'yourls_return_false' );
  58      }
  59  
  60      /**
  61       * Check for valid cookie name
  62       */
  63      public function test_cookie_name() {
  64          $this->assertTrue( is_string(yourls_cookie_name()) );
  65      }
  66  
  67      /**
  68       * Check for valid cookie value
  69       */
  70      public function test_cookie_value() {
  71          $this->assertTrue( is_string(yourls_cookie_value(rand_str())) );
  72      }
  73  
  74      /**
  75       * Check that the cookie value is filterable
  76       */
  77      public function test_cookie_value_is_filtered() {
  78          $this->add_filter( 'set_cookie_value', function() { return 'filtered_cookie_value'; } );
  79          $this->assertSame( 'filtered_cookie_value', yourls_cookie_value( rand_str() ) );
  80      }
  81  
  82      /**
  83       * Check for valid cookie life
  84       */
  85      public function test_cookie_life() {
  86          $this->assertTrue( is_int(yourls_get_cookie_life()) );
  87      }
  88  
  89      /**
  90       * Check that the cookie name is filterable
  91       */
  92      public function test_cookie_name_is_filtered() {
  93          $this->add_filter( 'cookie_name', function() { return 'my_custom_cookie_name'; } );
  94          $this->assertSame( 'my_custom_cookie_name', yourls_cookie_name() );
  95      }
  96  
  97      /**
  98       * Cookie attributes : returns the expected structure
  99       */
 100      public function test_cookie_attributes_structure() {
 101          $attr = yourls_cookie_attributes();
 102  
 103          $this->assertIsArray( $attr );
 104          $this->assertArrayHasKey( 'path',     $attr );
 105          $this->assertArrayHasKey( 'domain',   $attr );
 106          $this->assertArrayHasKey( 'secure',   $attr );
 107          $this->assertArrayHasKey( 'httponly', $attr );
 108  
 109          $this->assertIsString( $attr['path'] );
 110          $this->assertIsString( $attr['domain'] );
 111          $this->assertIsBool( $attr['secure'] );
 112          $this->assertIsBool( $attr['httponly'] );
 113      }
 114  
 115      /**
 116       * Cookie attributes : default values
 117       */
 118      public function test_cookie_attributes_defaults() {
 119          $attr = yourls_cookie_attributes();
 120  
 121          $this->assertSame( '/', $attr['path'] );
 122          $this->assertTrue( $attr['httponly'] );
 123      }
 124  
 125      /**
 126       * Cookie attributes : 'secure' follows yourls_is_ssl()
 127       */
 128      public function test_cookie_attributes_secure_follows_ssl() {
 129          $this->add_filter( 'is_ssl', 'yourls_return_true' );
 130          $this->assertTrue( yourls_cookie_attributes()['secure'] );
 131      }
 132  
 133      public function test_cookie_attributes_not_secure_without_ssl() {
 134          $this->add_filter( 'is_ssl', 'yourls_return_false' );
 135          $this->assertFalse( yourls_cookie_attributes()['secure'] );
 136      }
 137  
 138      /**
 139       * Cookie attributes : 'secure' can be forced regardless of SSL.
 140       * On top of being tested to make sure that feature will not get removed from the code, this is also used
 141       * here in unit tests.
 142       */
 143      public function test_cookie_attributes_secure_is_filtered() {
 144          // SSL off, but secure forced on
 145          $this->add_filter( 'is_ssl', 'yourls_return_false' );
 146          $this->add_filter( 'setcookie_secure', 'yourls_return_true' );
 147          $this->assertTrue( yourls_cookie_attributes()['secure'] );
 148      }
 149  
 150      /**
 151       * Cookie attributes : path, domain and httponly are filterable
 152       * On top of being tested to make sure that feature will not get removed from the code, this is also used
 153       * here in unit tests.
 154       */
 155      public function test_cookie_attributes_are_filtered() {
 156          $this->add_filter( 'setcookie_path',     function() { return '/sub/'; } );
 157          $this->add_filter( 'setcookie_domain',   function() { return 'sho.rt'; } );
 158          $this->add_filter( 'setcookie_httponly', 'yourls_return_false' );
 159  
 160          $attr = yourls_cookie_attributes();
 161  
 162          $this->assertSame( '/sub/', $attr['path'] );
 163          $this->assertSame( 'sho.rt', $attr['domain'] );
 164          $this->assertFalse( $attr['httponly'] );
 165      }
 166  
 167      /**
 168       * Cookie attributes : a 'localhost' domain is normalized to an empty string
 169       */
 170      public function test_cookie_attributes_localhost_domain_is_emptied() {
 171          $this->add_filter( 'setcookie_domain', function() { return 'localhost'; } );
 172          $this->assertSame( '', yourls_cookie_attributes()['domain'] );
 173      }
 174  
 175      /**
 176       * Cookie attributes : a null/false domain is normalized to an empty string
 177       */
 178      public function test_cookie_attributes_null_domain_is_emptied() {
 179          $this->add_filter( 'setcookie_domain', 'yourls_return_false' );
 180          $this->assertSame( '', yourls_cookie_attributes()['domain'] );
 181      }
 182  
 183      /**
 184       * Cookie name prefix : no prefix on a non-secure (HTTP) install
 185       */
 186      public function test_cookie_name_prefix_empty_when_not_secure() {
 187          $this->add_filter( 'is_ssl', 'yourls_return_false' );
 188          $this->assertSame( '', yourls_cookie_name_prefix() );
 189      }
 190  
 191      /**
 192       * Cookie name prefix : __Host- when Secure + host-only (no Domain) + Path=/
 193       */
 194      public function test_cookie_name_prefix_host_when_secure_hostonly_rootpath() {
 195          $this->add_filter( 'is_ssl', 'yourls_return_true' );
 196          $this->add_filter( 'setcookie_domain', function() { return ''; } );
 197          // path defaults to '/'
 198          $this->assertSame( '__Host-', yourls_cookie_name_prefix() );
 199      }
 200  
 201      /**
 202       * Cookie name prefix : __Secure- when Secure but a Domain attribute is set
 203       */
 204      public function test_cookie_name_prefix_secure_when_domain_is_set() {
 205          $this->add_filter( 'is_ssl', 'yourls_return_true' );
 206          $this->add_filter( 'setcookie_domain', function() { return 'sho.rt'; } );
 207          $this->assertSame( '__Secure-', yourls_cookie_name_prefix() );
 208      }
 209  
 210      /**
 211       * Cookie name prefix : __Secure- when Secure + host-only but path is not '/'
 212       */
 213      public function test_cookie_name_prefix_secure_when_path_not_root() {
 214          $this->add_filter( 'is_ssl', 'yourls_return_true' );
 215          $this->add_filter( 'setcookie_domain', function() { return ''; } );
 216          $this->add_filter( 'setcookie_path',   function() { return '/sub/'; } );
 217          $this->assertSame( '__Secure-', yourls_cookie_name_prefix() );
 218      }
 219  
 220      /**
 221       * Cookie name : carries the prefix matching the current attributes.
 222       * On HTTP, no prefix. On HTTPS, the name is prefixed.
 223       */
 224      public function test_cookie_name_has_no_prefix_on_http() {
 225          $this->add_filter( 'is_ssl', 'yourls_return_false' );
 226          $name = yourls_cookie_name();
 227          $this->assertStringStartsNotWith( '__Host-',   $name );
 228          $this->assertStringStartsNotWith( '__Secure-', $name );
 229      }
 230  
 231      public function test_cookie_name_has_host_prefix_on_https_hostonly() {
 232          $this->add_filter( 'is_ssl', 'yourls_return_true' );
 233          $this->add_filter( 'setcookie_domain', function() { return ''; } );
 234          $this->assertStringStartsWith( '__Host-', yourls_cookie_name() );
 235      }
 236  
 237      public function test_cookie_name_has_secure_prefix_on_https_with_domain() {
 238          $this->add_filter( 'is_ssl', 'yourls_return_true' );
 239          $this->add_filter( 'setcookie_domain', function() { return 'sho.rt'; } );
 240          $this->assertStringStartsWith( '__Secure-', yourls_cookie_name() );
 241      }
 242  
 243      /**
 244       * Cookie name : the prefix is the single source of truth shared with the
 245       * attributes, so the name actually reflects yourls_cookie_name_prefix().
 246       */
 247      public function test_cookie_name_matches_prefix() {
 248          $this->add_filter( 'is_ssl', 'yourls_return_true' );
 249          $this->add_filter( 'setcookie_domain', function() { return ''; } );
 250          $this->assertStringStartsWith( yourls_cookie_name_prefix(), yourls_cookie_name() );
 251      }
 252  
 253      /**
 254       * Test login with valid cookie - also check that cookie is set
 255       */
 256      public function test_login_valid_cookie() {
 257          global $yourls_user_passwords;
 258          $random_user = array_rand($yourls_user_passwords);
 259          $_COOKIE[yourls_cookie_name()] = yourls_cookie_value( $random_user );
 260          unset($_REQUEST);
 261  
 262          $this->assertSame( 0, yourls_did_action('pre_setcookie') );
 263          $this->assertTrue(yourls_check_auth_cookie());
 264          $this->assertTrue(yourls_is_valid_user());
 265          $this->assertSame( 1, yourls_did_action('pre_setcookie') );
 266      }
 267  
 268      /**
 269       * Test login with invalid cookie - also check that no cookie is set
 270       */
 271      public function test_login_invalid_cookie() {
 272          $_COOKIE[yourls_cookie_name()] = yourls_cookie_value( rand_str() );
 273          unset($_REQUEST);
 274  
 275          $this->assertSame( 0, yourls_did_action('pre_setcookie') );
 276          $this->assertFalse(yourls_check_auth_cookie());
 277          $this->assertNotTrue(yourls_is_valid_user());
 278          $this->assertSame( 0, yourls_did_action('pre_setcookie') );
 279      }
 280  
 281      /**
 282       * Logout request deletes the cookie : yourls_store_cookie('') fires
 283       * 'pre_setcookie' with a past expiry time.
 284       */
 285      public function test_logout_deletes_cookie() {
 286          $this->add_action( 'pre_setcookie', function( $args ) {
 287              // $args = array($user, $time, $path, $domain, $secure, $httponly)
 288              $GLOBALS['__test_logout_cookie_time'] = $args[1];
 289          } );
 290  
 291          $before = yourls_did_action( 'pre_setcookie' );
 292          yourls_store_cookie( '' );
 293          $after = yourls_did_action( 'pre_setcookie' );
 294  
 295          $this->assertSame( $before + 1, $after );
 296          // Deleting a cookie uses an expiry time in the past
 297          $this->assertLessThan( time(), $GLOBALS['__test_logout_cookie_time'] );
 298  
 299          unset( $GLOBALS['__test_logout_cookie_time'] );
 300      }
 301  
 302      /**
 303       * Storing a cookie for a real user uses a future expiry time
 304       */
 305      public function test_store_cookie_uses_future_expiry() {
 306          $this->add_action( 'pre_setcookie', function( $args ) {
 307              $GLOBALS['__test_store_cookie_time'] = $args[1];
 308          } );
 309  
 310          yourls_store_cookie( 'someuser' );
 311  
 312          $this->assertGreaterThan( time(), $GLOBALS['__test_store_cookie_time'] );
 313  
 314          unset( $GLOBALS['__test_store_cookie_time'] );
 315      }
 316  }


Generated: Sat Jun 13 05:10:47 2026 Cross-referenced by PHPXref 0.7.1