| [ Index ] |
PHP Cross Reference of YOURLS |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Sat Jun 13 05:10:47 2026 | Cross-referenced by PHPXref 0.7.1 |