[ Index ]

PHP Cross Reference of YOURLS

title

Body

[close]

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

   1  <?php
   2  /**
   3   * Tests with signatures
   4   */
   5  #[\PHPUnit\Framework\Attributes\Group('auth')]
   6  #[\PHPUnit\Framework\Attributes\Group('signatures')]
   7  class SigTest extends PHPUnit\Framework\TestCase {
   8  
   9      protected $backup_request;
  10  
  11      protected function setUp(): void {
  12          $this->backup_request = $_REQUEST;
  13      }
  14  
  15      protected function tearDown(): void {
  16          $_REQUEST = $this->backup_request;
  17          yourls_remove_all_filters( 'auth_signature' );
  18          yourls_remove_all_filters( 'auth_signature_length' );
  19      }
  20  
  21      /**
  22       * Check that empty signature isn't valid
  23       */
  24      public function test_signature_empty() {
  25          unset( $_REQUEST['signature'] );
  26          $this->assertFalse( yourls_check_signature() );
  27      }
  28  
  29      /**
  30       * Check that random signature isn't valid
  31       */
  32      public function test_signature_random() {
  33          $_REQUEST['signature'] = rand_str();
  34          $this->assertFalse( yourls_check_signature() );
  35      }
  36  
  37      /**
  38       * Check that empty signature and timestamp isn't valid
  39       */
  40      public function test_signature_timestamp_empty() {
  41          unset( $_REQUEST['signature'] );
  42          unset( $_REQUEST['timestamp'] );
  43          $this->assertFalse( yourls_check_signature_timestamp() );
  44      }
  45  
  46      /**
  47       * Check that random signature and timestamp isn't valid
  48       */
  49      public function test_signature_timestamp_random() {
  50          $_REQUEST['signature'] = rand_str();
  51          $_REQUEST['timestamp'] = rand_str();
  52          $this->assertFalse( yourls_check_signature_timestamp() );
  53      }
  54  
  55      /**
  56       * Check that valid sha256 (default algo) timestamped sig is valid
  57       */
  58      public function test_signature_timestamp_sha256() {
  59          $timestamp = time();
  60          $_REQUEST['timestamp'] = $timestamp;
  61  
  62          global $yourls_user_passwords;
  63          $random_user = array_rand($yourls_user_passwords);
  64          $signature = yourls_auth_signature($random_user);
  65  
  66          $hash = hash( 'sha256', $timestamp . $signature );
  67          $_REQUEST['signature'] = $hash;
  68          $this->assertTrue( yourls_check_signature_timestamp() );
  69  
  70          $hash = hash( 'sha256', $signature . $timestamp );
  71          $_REQUEST['signature'] = $hash;
  72          $this->assertTrue( yourls_check_signature_timestamp() );
  73      }
  74  
  75      /**
  76       * Check that valid hashed timestamped sig with a specified algo is valid
  77       */
  78      public function test_signature_timestamp_hash() {
  79          $timestamp = time();
  80          $_REQUEST['timestamp'] = $timestamp;
  81  
  82          global $yourls_user_passwords;
  83          $random_user = array_rand($yourls_user_passwords);
  84          $signature = yourls_auth_signature($random_user);
  85  
  86          $algos = [ 'sha256', 'sha384', 'sha512' ];
  87  
  88          foreach( $algos as $algo ) {
  89              $hash = hash( $algo, $timestamp . $signature );
  90              $_REQUEST['hash'] = $algo;
  91              $_REQUEST['signature'] = $hash;
  92              $this->assertTrue( yourls_check_signature_timestamp() );
  93  
  94              $hash = hash( $algo, $signature . $timestamp );
  95              $_REQUEST['signature'] = $hash;
  96              $this->assertTrue( yourls_check_signature_timestamp() );
  97  
  98              $_REQUEST['hash'] = rand_str();
  99              $this->assertFalse( yourls_check_signature_timestamp() );
 100          }
 101      }
 102  
 103      /**
 104       * Make sure we always define a default hash algo and an allowed hash algos list, so that future update of function
 105       * will maintain the same behavior (allow algo other than sha256, sha384 and sha512 via filter)
 106       */
 107      public function test_signature_timestamp_default_algo() {
 108          $this->assertIsString( yourls_default_hash_algo() );
 109          $this->assertIsArray( yourls_allowed_hash_algos() );
 110      }
 111  
 112      /**
 113       * Provide valid and invalid timestamps as compared to current time and nonce life
 114       */
 115      public static function timestamps(): \Iterator {
 116          $now = time();
 117          $little_in_the_future = $now + ( YOURLS_NONCE_LIFE / 2 );
 118          $little_in_the_past   = $now - ( YOURLS_NONCE_LIFE / 2 );
 119          $far_in_the_future    = $now + ( YOURLS_NONCE_LIFE * 2 );
 120          $far_in_the_past      = $now - ( YOURLS_NONCE_LIFE * 2 );
 121          yield array( 0, false );
 122          yield array( $now, true );
 123          yield array( $little_in_the_future, true );
 124          yield array( $little_in_the_past, true );
 125          yield array( $far_in_the_future, false );
 126          yield array( $far_in_the_past, false );
 127      }
 128  
 129      /**
 130       * Check that timestamps are correctly handled (too old = bad, too future = bad, ...)
 131       */
 132      #[\PHPUnit\Framework\Attributes\DataProvider('timestamps')]
 133      public function test_check_timestamp( $timestamp, $is_valid ) {
 134          $this->assertSame(yourls_check_timestamp( $timestamp ), $is_valid );
 135      }
 136  
 137      /**
 138       * Check that auth signature length defaults to 32 and is an integer
 139       */
 140      public function test_auth_signature_length_default() {
 141          $this->assertSame( 32, yourls_auth_signature_length() );
 142      }
 143  
 144      /**
 145       * Check that auth signature length can be filtered
 146       */
 147      public function test_auth_signature_length_filtered() {
 148          $hook = 'auth_signature_length';
 149          // Filter with an int, and with a non int that must be cast to int
 150          yourls_add_filter( $hook, fn() => 16 );
 151          $this->assertSame( 16, yourls_auth_signature_length() );
 152          yourls_remove_all_filters( $hook );
 153  
 154          yourls_add_filter( $hook, fn() => '24' );
 155          $this->assertSame( 24, yourls_auth_signature_length() );
 156          yourls_remove_all_filters( $hook );
 157      }
 158  
 159      /**
 160       * Check that auth signature is constant for a given user and differs between users
 161       */
 162      public function test_auth_signature_is_deterministic_and_user_specific() {
 163          $this->assertSame( yourls_auth_signature( 'ozh' ), yourls_auth_signature( 'ozh' ) );
 164          $this->assertNotSame( yourls_auth_signature( 'dgw' ), yourls_auth_signature( 'Leo' ) );
 165      }
 166  
 167      /**
 168       * Check that auth signature with a falsy username falls back to YOURLS_USER, or errors when none is defined
 169       */
 170      public function test_auth_signature_no_username() {
 171          if ( defined( 'YOURLS_USER' ) && YOURLS_USER ) {
 172              // A falsy username falls back to the currently logged in user
 173              $this->assertSame( yourls_auth_signature( YOURLS_USER ), yourls_auth_signature() );
 174              $this->assertSame( yourls_auth_signature( YOURLS_USER ), yourls_auth_signature( false ) );
 175              $this->assertSame( yourls_auth_signature( YOURLS_USER ), yourls_auth_signature( '' ) );
 176          } else {
 177              // No username and no logged in user yields the error message
 178              $this->assertSame( 'Cannot generate auth signature: no username', yourls_auth_signature() );
 179              $this->assertSame( 'Cannot generate auth signature: no username', yourls_auth_signature( false ) );
 180              $this->assertSame( 'Cannot generate auth signature: no username', yourls_auth_signature( '' ) );
 181          }
 182      }
 183  
 184      /**
 185       * Check that auth signature honors its length filter
 186       */
 187      public function test_auth_signature_honors_length_filter() {
 188          yourls_add_filter( 'auth_signature_length', fn() => 10 );
 189  
 190          $signature = yourls_auth_signature( 'ozh' );
 191          $this->assertSame( 10, strlen( $signature ) );
 192      }
 193  
 194      /**
 195       * Check that auth signature can be filtered
 196       */
 197      public function test_auth_signature_filtered() {
 198          yourls_add_filter( 'auth_signature', fn( $signature, $username ) => 'filtered:' . $username, 10, 2 );
 199  
 200          $this->assertSame( 'filtered:ozh', yourls_auth_signature( 'ozh' ) );
 201      }
 202  
 203  }


Generated: Thu Jun 18 05:10:24 2026 Cross-referenced by PHPXref 0.7.1