| 
									
										
										
										
											2020-10-16 07:27:36 +08:00
										 |  |  | <?php namespace Tests\User; | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-21 02:53:01 +08:00
										 |  |  | use BookStack\Actions\ActivityType; | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | use BookStack\Api\ApiToken; | 
					
						
							|  |  |  | use Carbon\Carbon; | 
					
						
							|  |  |  | use Tests\TestCase; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UserApiTokenTest extends TestCase | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected $testTokenData = [ | 
					
						
							|  |  |  |         '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
										 |  |  |     ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_tokens_section_not_visible_without_access_api_permission() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-12-31 03:42:46 +08:00
										 |  |  |         $user = $this->getViewer(); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->actingAs($user)->get($user->getEditUrl()); | 
					
						
							|  |  |  |         $resp->assertDontSeeText('API Tokens'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $this->giveUserPermissions($user, ['access-api']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->actingAs($user)->get($user->getEditUrl()); | 
					
						
							|  |  |  |         $resp->assertSeeText('API Tokens'); | 
					
						
							|  |  |  |         $resp->assertSeeText('Create Token'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_those_with_manage_users_can_view_other_user_tokens_but_not_create() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $viewer = $this->getViewer(); | 
					
						
							|  |  |  |         $editor = $this->getEditor(); | 
					
						
							| 
									
										
										
										
											2019-12-31 03:42:46 +08:00
										 |  |  |         $this->giveUserPermissions($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() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $editor = $this->getEditor(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->asAdmin()->get($editor->getEditUrl('/create-api-token')); | 
					
						
							|  |  |  |         $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
										 |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); | 
					
						
							|  |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  |         $resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id)); | 
					
						
							|  |  |  |         $this->assertDatabaseHas('api_tokens', [ | 
					
						
							|  |  |  |             'user_id' => $editor->id, | 
					
						
							|  |  |  |             'name' => $this->testTokenData['name'], | 
					
						
							|  |  |  |             '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
										 |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2019-12-30 04:07:28 +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() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $editor = $this->getEditor(); | 
					
						
							| 
									
										
										
										
											2019-12-30 04:18:37 +08:00
										 |  |  |         $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), ['name' => 'No expiry token', 'expires_at' => '']); | 
					
						
							| 
									
										
										
										
											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), | 
					
						
							|  |  |  |             "Token expiry set at 100 years in future" | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_created_token_displays_on_profile_page() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $editor = $this->getEditor(); | 
					
						
							|  |  |  |         $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); | 
					
						
							|  |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->get($editor->getEditUrl()); | 
					
						
							|  |  |  |         $resp->assertElementExists('#api_tokens'); | 
					
						
							|  |  |  |         $resp->assertElementContains('#api_tokens', $token->name); | 
					
						
							| 
									
										
										
										
											2019-12-30 04:07:28 +08:00
										 |  |  |         $resp->assertElementContains('#api_tokens', $token->token_id); | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |         $resp->assertElementContains('#api_tokens', $token->expires_at->format('Y-m-d')); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 04:07:28 +08:00
										 |  |  |     public function test_secret_shown_once_after_creation() | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $editor = $this->getEditor(); | 
					
						
							|  |  |  |         $resp = $this->asAdmin()->followingRedirects()->post($editor->getEditUrl('/create-api-token'), $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)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->get($editor->getEditUrl('/api-tokens/' . $token->id)); | 
					
						
							|  |  |  |         $resp->assertDontSeeText('Client Secret'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function test_token_update() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $editor = $this->getEditor(); | 
					
						
							|  |  |  |         $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); | 
					
						
							|  |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  |         $updateData = [ | 
					
						
							|  |  |  |             'name' => 'My updated token', | 
					
						
							|  |  |  |             'expires_at' => '2011-01-01', | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), $updateData); | 
					
						
							|  |  |  |         $resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $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() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $editor = $this->getEditor(); | 
					
						
							|  |  |  |         $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); | 
					
						
							|  |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), [ | 
					
						
							|  |  |  |             'name' => 'My updated token', | 
					
						
							|  |  |  |             'expires_at' => '', | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |         $token->refresh(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $over = Carbon::now()->addYears(101); | 
					
						
							|  |  |  |         $under = Carbon::now()->addYears(99); | 
					
						
							|  |  |  |         $this->assertTrue( | 
					
						
							|  |  |  |             ($token->expires_at < $over && $token->expires_at > $under), | 
					
						
							|  |  |  |             "Token expiry set at 100 years in future" | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 03:46:46 +08:00
										 |  |  |     public function test_token_delete() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $editor = $this->getEditor(); | 
					
						
							|  |  |  |         $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); | 
					
						
							|  |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $tokenUrl = $editor->getEditUrl('/api-tokens/' . $token->id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->get($tokenUrl . '/delete'); | 
					
						
							|  |  |  |         $resp->assertSeeText('Delete Token'); | 
					
						
							|  |  |  |         $resp->assertSeeText($token->name); | 
					
						
							|  |  |  |         $resp->assertElementExists('form[action="'.$tokenUrl.'"]'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $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() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $viewer = $this->getViewer(); | 
					
						
							|  |  |  |         $editor = $this->getEditor(); | 
					
						
							|  |  |  |         $this->giveUserPermissions($editor, ['users-manage']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $this->asAdmin()->post($viewer->getEditUrl('/create-api-token'), $this->testTokenData); | 
					
						
							|  |  |  |         $token = ApiToken::query()->latest()->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->actingAs($editor)->get($viewer->getEditUrl('/api-tokens/' . $token->id)); | 
					
						
							|  |  |  |         $resp->assertStatus(200); | 
					
						
							|  |  |  |         $resp->assertSeeText('Delete Token'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $resp = $this->actingAs($editor)->delete($viewer->getEditUrl('/api-tokens/' . $token->id)); | 
					
						
							|  |  |  |         $resp->assertRedirect($viewer->getEditUrl('#api_tokens')); | 
					
						
							|  |  |  |         $this->assertDatabaseMissing('api_tokens', ['id' => $token->id]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |