| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Tests\User; | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | use BookStack\Activity\ActivityType; | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | use BookStack\Api\ApiToken; | 
					
						
							|  |  |  | use Carbon\Carbon; | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  | use Illuminate\Support\Facades\Hash; | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | use Tests\TestCase; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UserApiTokenTest extends TestCase | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |     protected array $testTokenData = [ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |         'name'       => 'My test API token', | 
					
						
							| 
									
										
										
										
											2019-12-30 04:18:37 +08:00
										 |  |  |         'expires_at' => '2050-04-01', | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     ]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |     public function test_tokens_section_not_visible_in_my_account_without_access_api_permission() | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $user = $this->users->viewer(); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->actingAs($user)->get('/my-account/auth'); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $resp->assertDontSeeText('API Tokens'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $this->permissions->grantUserRolePermissions($user, ['access-api']); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->actingAs($user)->get('/my-account/auth'); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $resp->assertSeeText('API Tokens'); | 
					
						
							|  |  |  |         $resp->assertSeeText('Create Token'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_those_with_manage_users_can_view_other_user_tokens_but_not_create() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $viewer = $this->users->viewer(); | 
					
						
							|  |  |  |         $editor = $this->users->editor(); | 
					
						
							|  |  |  |         $this->permissions->grantUserRolePermissions($viewer, ['users-manage']); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-31 03:42:46 +08:00
										 |  |  |         $resp = $this->actingAs($viewer)->get($editor->getEditUrl()); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $resp->assertSeeText('API Tokens'); | 
					
						
							|  |  |  |         $resp->assertDontSeeText('Create Token'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_create_api_token() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $editor = $this->users->editor(); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->asAdmin()->get("/api-tokens/{$editor->id}/create"); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $resp->assertStatus(200); | 
					
						
							|  |  |  |         $resp->assertSee('Create API Token'); | 
					
						
							| 
									
										
										
										
											2019-12-30 04:07:28 +08:00
										 |  |  |         $resp->assertSee('Token Secret'); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->post("/api-tokens/{$editor->id}/create", $this->testTokenData); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp->assertRedirect("/api-tokens/{$editor->id}/{$token->id}"); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $this->assertDatabaseHas('api_tokens', [ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'user_id'    => $editor->id, | 
					
						
							|  |  |  |             'name'       => $this->testTokenData['name'], | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |             'expires_at' => $this->testTokenData['expires_at'], | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Check secret token
 | 
					
						
							|  |  |  |         $this->assertSessionHas('api-token-secret:' . $token->id); | 
					
						
							|  |  |  |         $secret = session('api-token-secret:' . $token->id); | 
					
						
							|  |  |  |         $this->assertDatabaseMissing('api_tokens', [ | 
					
						
							| 
									
										
										
										
											2019-12-30 04:07:28 +08:00
										 |  |  |             'secret' => $secret, | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $this->assertTrue(Hash::check($secret, $token->secret)); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 04:07:28 +08:00
										 |  |  |         $this->assertTrue(strlen($token->token_id) === 32); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $this->assertTrue(strlen($secret) === 32); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $this->assertSessionHas('success'); | 
					
						
							| 
									
										
										
										
											2020-11-21 02:53:01 +08:00
										 |  |  |         $this->assertActivityExists(ActivityType::API_TOKEN_CREATE); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_create_with_no_expiry_sets_expiry_hundred_years_away() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $editor = $this->users->editor(); | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->asAdmin()->post("/api-tokens/{$editor->id}/create", ['name' => 'No expiry token', 'expires_at' => '']); | 
					
						
							|  |  |  |         $resp->assertRedirect(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $over = Carbon::now()->addYears(101); | 
					
						
							|  |  |  |         $under = Carbon::now()->addYears(99); | 
					
						
							|  |  |  |         $this->assertTrue( | 
					
						
							|  |  |  |             ($token->expires_at < $over && $token->expires_at > $under), | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'Token expiry set at 100 years in future' | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_created_token_displays_on_profile_page() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $editor = $this->users->editor(); | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->asAdmin()->post("/api-tokens/{$editor->id}/create", $this->testTokenData); | 
					
						
							|  |  |  |         $resp->assertRedirect(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->get($editor->getEditUrl()); | 
					
						
							| 
									
										
										
										
											2022-07-23 22:10:18 +08:00
										 |  |  |         $this->withHtml($resp)->assertElementExists('#api_tokens'); | 
					
						
							|  |  |  |         $this->withHtml($resp)->assertElementContains('#api_tokens', $token->name); | 
					
						
							|  |  |  |         $this->withHtml($resp)->assertElementContains('#api_tokens', $token->token_id); | 
					
						
							|  |  |  |         $this->withHtml($resp)->assertElementContains('#api_tokens', $token->expires_at->format('Y-m-d')); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 04:07:28 +08:00
										 |  |  |     public function test_secret_shown_once_after_creation() | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $editor = $this->users->editor(); | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->asAdmin()->followingRedirects()->post("/api-tokens/{$editor->id}/create", $this->testTokenData); | 
					
						
							| 
									
										
										
										
											2019-12-30 04:07:28 +08:00
										 |  |  |         $resp->assertSeeText('Token Secret'); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  |         $this->assertNull(session('api-token-secret:' . $token->id)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->get("/api-tokens/{$editor->id}/{$token->id}"); | 
					
						
							|  |  |  |         $resp->assertOk(); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $resp->assertDontSeeText('Client Secret'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_token_update() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $editor = $this->users->editor(); | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $this->asAdmin()->post("/api-tokens/{$editor->id}/create", $this->testTokenData); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  |         $updateData = [ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'name'       => 'My updated token', | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |             'expires_at' => '2011-01-01', | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->put("/api-tokens/{$editor->id}/{$token->id}", $updateData); | 
					
						
							|  |  |  |         $resp->assertRedirect("/api-tokens/{$editor->id}/{$token->id}"); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $this->assertDatabaseHas('api_tokens', array_merge($updateData, ['id' => $token->id])); | 
					
						
							|  |  |  |         $this->assertSessionHas('success'); | 
					
						
							| 
									
										
										
										
											2020-11-21 02:53:01 +08:00
										 |  |  |         $this->assertActivityExists(ActivityType::API_TOKEN_UPDATE); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 04:18:37 +08:00
										 |  |  |     public function test_token_update_with_blank_expiry_sets_to_hundred_years_away() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $editor = $this->users->editor(); | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $this->asAdmin()->post("/api-tokens/{$editor->id}/create", $this->testTokenData); | 
					
						
							| 
									
										
										
										
											2019-12-30 04:18:37 +08:00
										 |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $this->put("/api-tokens/{$editor->id}/{$token->id}", [ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'name'       => 'My updated token', | 
					
						
							| 
									
										
										
										
											2019-12-30 04:18:37 +08:00
										 |  |  |             'expires_at' => '', | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         ])->assertRedirect(); | 
					
						
							| 
									
										
										
										
											2019-12-30 04:18:37 +08:00
										 |  |  |         $token->refresh(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $over = Carbon::now()->addYears(101); | 
					
						
							|  |  |  |         $under = Carbon::now()->addYears(99); | 
					
						
							|  |  |  |         $this->assertTrue( | 
					
						
							|  |  |  |             ($token->expires_at < $over && $token->expires_at > $under), | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'Token expiry set at 100 years in future' | 
					
						
							| 
									
										
										
										
											2019-12-30 04:18:37 +08:00
										 |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     public function test_token_delete() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $editor = $this->users->editor(); | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $this->asAdmin()->post("/api-tokens/{$editor->id}/create", $this->testTokenData); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $tokenUrl = "/api-tokens/{$editor->id}/{$token->id}"; | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->get($tokenUrl . '/delete'); | 
					
						
							|  |  |  |         $resp->assertSeeText('Delete Token'); | 
					
						
							|  |  |  |         $resp->assertSeeText($token->name); | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $this->withHtml($resp)->assertElementExists('form[action$="' . $tokenUrl . '"]'); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->delete($tokenUrl); | 
					
						
							|  |  |  |         $resp->assertRedirect($editor->getEditUrl('#api_tokens')); | 
					
						
							|  |  |  |         $this->assertDatabaseMissing('api_tokens', ['id' => $token->id]); | 
					
						
							| 
									
										
										
										
											2020-11-21 02:53:01 +08:00
										 |  |  |         $this->assertActivityExists(ActivityType::API_TOKEN_DELETE); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_user_manage_can_delete_token_without_api_permission_themselves() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-21 19:08:34 +08:00
										 |  |  |         $viewer = $this->users->viewer(); | 
					
						
							|  |  |  |         $editor = $this->users->editor(); | 
					
						
							|  |  |  |         $this->permissions->grantUserRolePermissions($editor, ['users-manage']); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $this->asAdmin()->post("/api-tokens/{$viewer->id}/create", $this->testTokenData); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->actingAs($editor)->get("/api-tokens/{$viewer->id}/{$token->id}"); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $resp->assertStatus(200); | 
					
						
							|  |  |  |         $resp->assertSeeText('Delete Token'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  |         $resp = $this->actingAs($editor)->delete("/api-tokens/{$viewer->id}/{$token->id}"); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $resp->assertRedirect($viewer->getEditUrl('#api_tokens')); | 
					
						
							|  |  |  |         $this->assertDatabaseMissing('api_tokens', ['id' => $token->id]); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-10-19 21:18:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     public function test_return_routes_change_depending_on_entry_context() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $user = $this->users->admin(); | 
					
						
							|  |  |  |         $returnByContext = [ | 
					
						
							|  |  |  |             'settings' => url("/settings/users/{$user->id}/#api_tokens"), | 
					
						
							|  |  |  |             'my-account' => url('/my-account/auth#api_tokens'), | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($returnByContext as $context => $returnUrl) { | 
					
						
							|  |  |  |             $resp = $this->actingAs($user)->get("/api-tokens/{$user->id}/create?context={$context}"); | 
					
						
							|  |  |  |             $this->withHtml($resp)->assertLinkExists($returnUrl, 'Cancel'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $this->post("/api-tokens/{$user->id}/create", $this->testTokenData); | 
					
						
							|  |  |  |             $token = $user->apiTokens()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $resp = $this->get($token->getUrl()); | 
					
						
							|  |  |  |             $this->withHtml($resp)->assertLinkExists($returnUrl, 'Back'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $resp = $this->delete($token->getUrl()); | 
					
						
							|  |  |  |             $resp->assertRedirect($returnUrl); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_context_assumed_for_editing_tokens_of_another_user() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $user = $this->users->viewer(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->asAdmin()->get("/api-tokens/{$user->id}/create?context=my-account"); | 
					
						
							|  |  |  |         $this->withHtml($resp)->assertLinkExists($user->getEditUrl('#api_tokens'), 'Cancel'); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | } |