recovery-mode-key-service.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <?php
  2. /**
  3. * @group error-protection
  4. */
  5. class Tests_Recovery_Mode_Key_Service extends WP_UnitTestCase {
  6. /**
  7. * @ticket 46130
  8. *
  9. * @covers WP_Recovery_Mode_Cookie_Service::generate_recovery_mode_token
  10. * @covers WP_Recovery_Mode_Cookie_Service::generate_and_store_recovery_mode_key
  11. */
  12. public function test_generate_and_store_recovery_mode_key_returns_recovery_key() {
  13. $service = new WP_Recovery_Mode_Key_Service();
  14. $token = $service->generate_recovery_mode_token();
  15. $key = $service->generate_and_store_recovery_mode_key( $token );
  16. $this->assertNotWPError( $key );
  17. }
  18. /**
  19. * @ticket 46130
  20. *
  21. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  22. */
  23. public function test_validate_recovery_mode_key_returns_wp_error_if_no_key_set() {
  24. $service = new WP_Recovery_Mode_Key_Service();
  25. $error = $service->validate_recovery_mode_key( '', 'abcd', HOUR_IN_SECONDS );
  26. $this->assertWPError( $error );
  27. $this->assertSame( 'token_not_found', $error->get_error_code() );
  28. }
  29. /**
  30. * @ticket 46130
  31. *
  32. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  33. */
  34. public function test_validate_recovery_mode_key_returns_wp_error_if_data_missing() {
  35. update_option( 'recovery_keys', 'gibberish' );
  36. $service = new WP_Recovery_Mode_Key_Service();
  37. $error = $service->validate_recovery_mode_key( '', 'abcd', HOUR_IN_SECONDS );
  38. $this->assertWPError( $error );
  39. $this->assertSame( 'token_not_found', $error->get_error_code() );
  40. }
  41. /**
  42. * @ticket 46130
  43. *
  44. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  45. */
  46. public function test_validate_recovery_mode_key_returns_wp_error_if_bad() {
  47. update_option( 'recovery_keys', array( 'token' => 'gibberish' ) );
  48. $service = new WP_Recovery_Mode_Key_Service();
  49. $error = $service->validate_recovery_mode_key( 'token', 'abcd', HOUR_IN_SECONDS );
  50. $this->assertWPError( $error );
  51. $this->assertSame( 'invalid_recovery_key_format', $error->get_error_code() );
  52. }
  53. /**
  54. * @ticket 46130
  55. *
  56. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  57. */
  58. public function test_validate_recovery_mode_key_returns_wp_error_if_stored_format_is_invalid() {
  59. $token = wp_generate_password( 22, false );
  60. update_option( 'recovery_keys', array( $token => 'gibberish' ) );
  61. $service = new WP_Recovery_Mode_Key_Service();
  62. $error = $service->validate_recovery_mode_key( $token, 'abcd', HOUR_IN_SECONDS );
  63. $this->assertWPError( $error );
  64. $this->assertSame( 'invalid_recovery_key_format', $error->get_error_code() );
  65. }
  66. /**
  67. * @ticket 46130
  68. *
  69. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  70. */
  71. public function test_validate_recovery_mode_key_returns_wp_error_if_empty_key() {
  72. $service = new WP_Recovery_Mode_Key_Service();
  73. $token = $service->generate_recovery_mode_token();
  74. $service->generate_and_store_recovery_mode_key( $token );
  75. $error = $service->validate_recovery_mode_key( $token, '', HOUR_IN_SECONDS );
  76. $this->assertWPError( $error );
  77. $this->assertSame( 'hash_mismatch', $error->get_error_code() );
  78. }
  79. /**
  80. * @ticket 46130
  81. *
  82. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  83. */
  84. public function test_validate_recovery_mode_key_returns_wp_error_if_hash_mismatch() {
  85. $service = new WP_Recovery_Mode_Key_Service();
  86. $token = $service->generate_recovery_mode_token();
  87. $service->generate_and_store_recovery_mode_key( $token );
  88. $error = $service->validate_recovery_mode_key( $token, 'abcd', HOUR_IN_SECONDS );
  89. $this->assertWPError( $error );
  90. $this->assertSame( 'hash_mismatch', $error->get_error_code() );
  91. }
  92. /**
  93. * @ticket 46130
  94. *
  95. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  96. */
  97. public function test_validate_recovery_mode_key_returns_wp_error_if_expired() {
  98. $service = new WP_Recovery_Mode_Key_Service();
  99. $token = $service->generate_recovery_mode_token();
  100. $key = $service->generate_and_store_recovery_mode_key( $token );
  101. $records = get_option( 'recovery_keys' );
  102. $records[ $token ]['created_at'] = time() - HOUR_IN_SECONDS - 30;
  103. update_option( 'recovery_keys', $records );
  104. $error = $service->validate_recovery_mode_key( $token, $key, HOUR_IN_SECONDS );
  105. $this->assertWPError( $error );
  106. $this->assertSame( 'key_expired', $error->get_error_code() );
  107. }
  108. /**
  109. * @ticket 46130
  110. *
  111. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  112. */
  113. public function test_validate_recovery_mode_key_returns_true_for_valid_key() {
  114. $service = new WP_Recovery_Mode_Key_Service();
  115. $token = $service->generate_recovery_mode_token();
  116. $key = $service->generate_and_store_recovery_mode_key( $token );
  117. $this->assertTrue( $service->validate_recovery_mode_key( $token, $key, HOUR_IN_SECONDS ) );
  118. }
  119. /**
  120. * @ticket 46595
  121. *
  122. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  123. */
  124. public function test_validate_recovery_mode_key_returns_error_if_token_used_more_than_once() {
  125. $service = new WP_Recovery_Mode_Key_Service();
  126. $token = $service->generate_recovery_mode_token();
  127. $key = $service->generate_and_store_recovery_mode_key( $token );
  128. $this->assertTrue( $service->validate_recovery_mode_key( $token, $key, HOUR_IN_SECONDS ) );
  129. // Data should be remove by first call.
  130. $error = $service->validate_recovery_mode_key( $token, $key, HOUR_IN_SECONDS );
  131. $this->assertWPError( $error );
  132. $this->assertSame( 'token_not_found', $error->get_error_code() );
  133. }
  134. /**
  135. * @ticket 46595
  136. *
  137. * @covers WP_Recovery_Mode_Cookie_Service::generate_recovery_mode_token
  138. * @covers WP_Recovery_Mode_Cookie_Service::generate_and_store_recovery_mode_key
  139. * @covers WP_Recovery_Mode_Cookie_Service::validate_recovery_mode_key
  140. */
  141. public function test_validate_recovery_mode_key_returns_error_if_token_used_more_than_once_more_than_key_stored() {
  142. $service = new WP_Recovery_Mode_Key_Service();
  143. // Create an extra key.
  144. $token = $service->generate_recovery_mode_token();
  145. $service->generate_and_store_recovery_mode_key( $token );
  146. $token = $service->generate_recovery_mode_token();
  147. $key = $service->generate_and_store_recovery_mode_key( $token );
  148. $this->assertTrue( $service->validate_recovery_mode_key( $token, $key, HOUR_IN_SECONDS ) );
  149. // Data should be remove by first call.
  150. $error = $service->validate_recovery_mode_key( $token, $key, HOUR_IN_SECONDS );
  151. $this->assertWPError( $error );
  152. $this->assertSame( 'token_not_found', $error->get_error_code() );
  153. }
  154. /**
  155. * @ticket 46595
  156. *
  157. * @covers WP_Recovery_Mode_Cookie_Service::clean_expired_keys
  158. */
  159. public function test_clean_expired_keys() {
  160. $service = new WP_Recovery_Mode_Key_Service();
  161. $token = $service->generate_recovery_mode_token();
  162. $service->generate_and_store_recovery_mode_key( $token );
  163. $records = get_option( 'recovery_keys' );
  164. $records[ $token ]['created_at'] = time() - HOUR_IN_SECONDS - 30;
  165. update_option( 'recovery_keys', $records );
  166. $service->clean_expired_keys( HOUR_IN_SECONDS );
  167. $this->assertEmpty( get_option( 'recovery_keys' ) );
  168. }
  169. }