5 use BookStack\Actions\ActivityType;
6 use BookStack\Api\ApiToken;
10 class UserApiTokenTest extends TestCase
12 protected $testTokenData = [
13 'name' => 'My test API token',
14 'expires_at' => '2050-04-01',
17 public function test_tokens_section_not_visible_without_access_api_permission()
19 $user = $this->getViewer();
21 $resp = $this->actingAs($user)->get($user->getEditUrl());
22 $resp->assertDontSeeText('API Tokens');
24 $this->giveUserPermissions($user, ['access-api']);
26 $resp = $this->actingAs($user)->get($user->getEditUrl());
27 $resp->assertSeeText('API Tokens');
28 $resp->assertSeeText('Create Token');
31 public function test_those_with_manage_users_can_view_other_user_tokens_but_not_create()
33 $viewer = $this->getViewer();
34 $editor = $this->getEditor();
35 $this->giveUserPermissions($viewer, ['users-manage']);
37 $resp = $this->actingAs($viewer)->get($editor->getEditUrl());
38 $resp->assertSeeText('API Tokens');
39 $resp->assertDontSeeText('Create Token');
42 public function test_create_api_token()
44 $editor = $this->getEditor();
46 $resp = $this->asAdmin()->get($editor->getEditUrl('/create-api-token'));
47 $resp->assertStatus(200);
48 $resp->assertSee('Create API Token');
49 $resp->assertSee('Token Secret');
51 $resp = $this->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
52 $token = ApiToken::query()->latest()->first();
53 $resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id));
54 $this->assertDatabaseHas('api_tokens', [
55 'user_id' => $editor->id,
56 'name' => $this->testTokenData['name'],
57 'expires_at' => $this->testTokenData['expires_at'],
61 $this->assertSessionHas('api-token-secret:' . $token->id);
62 $secret = session('api-token-secret:' . $token->id);
63 $this->assertDatabaseMissing('api_tokens', [
66 $this->assertTrue(\Hash::check($secret, $token->secret));
68 $this->assertTrue(strlen($token->token_id) === 32);
69 $this->assertTrue(strlen($secret) === 32);
71 $this->assertSessionHas('success');
72 $this->assertActivityExists(ActivityType::API_TOKEN_CREATE);
75 public function test_create_with_no_expiry_sets_expiry_hundred_years_away()
77 $editor = $this->getEditor();
78 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), ['name' => 'No expiry token', 'expires_at' => '']);
79 $token = ApiToken::query()->latest()->first();
81 $over = Carbon::now()->addYears(101);
82 $under = Carbon::now()->addYears(99);
84 ($token->expires_at < $over && $token->expires_at > $under),
85 'Token expiry set at 100 years in future'
89 public function test_created_token_displays_on_profile_page()
91 $editor = $this->getEditor();
92 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
93 $token = ApiToken::query()->latest()->first();
95 $resp = $this->get($editor->getEditUrl());
96 $resp->assertElementExists('#api_tokens');
97 $resp->assertElementContains('#api_tokens', $token->name);
98 $resp->assertElementContains('#api_tokens', $token->token_id);
99 $resp->assertElementContains('#api_tokens', $token->expires_at->format('Y-m-d'));
102 public function test_secret_shown_once_after_creation()
104 $editor = $this->getEditor();
105 $resp = $this->asAdmin()->followingRedirects()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
106 $resp->assertSeeText('Token Secret');
108 $token = ApiToken::query()->latest()->first();
109 $this->assertNull(session('api-token-secret:' . $token->id));
111 $resp = $this->get($editor->getEditUrl('/api-tokens/' . $token->id));
112 $resp->assertDontSeeText('Client Secret');
115 public function test_token_update()
117 $editor = $this->getEditor();
118 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
119 $token = ApiToken::query()->latest()->first();
121 'name' => 'My updated token',
122 'expires_at' => '2011-01-01',
125 $resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), $updateData);
126 $resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id));
128 $this->assertDatabaseHas('api_tokens', array_merge($updateData, ['id' => $token->id]));
129 $this->assertSessionHas('success');
130 $this->assertActivityExists(ActivityType::API_TOKEN_UPDATE);
133 public function test_token_update_with_blank_expiry_sets_to_hundred_years_away()
135 $editor = $this->getEditor();
136 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
137 $token = ApiToken::query()->latest()->first();
139 $resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), [
140 'name' => 'My updated token',
145 $over = Carbon::now()->addYears(101);
146 $under = Carbon::now()->addYears(99);
148 ($token->expires_at < $over && $token->expires_at > $under),
149 'Token expiry set at 100 years in future'
153 public function test_token_delete()
155 $editor = $this->getEditor();
156 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
157 $token = ApiToken::query()->latest()->first();
159 $tokenUrl = $editor->getEditUrl('/api-tokens/' . $token->id);
161 $resp = $this->get($tokenUrl . '/delete');
162 $resp->assertSeeText('Delete Token');
163 $resp->assertSeeText($token->name);
164 $resp->assertElementExists('form[action="' . $tokenUrl . '"]');
166 $resp = $this->delete($tokenUrl);
167 $resp->assertRedirect($editor->getEditUrl('#api_tokens'));
168 $this->assertDatabaseMissing('api_tokens', ['id' => $token->id]);
169 $this->assertActivityExists(ActivityType::API_TOKEN_DELETE);
172 public function test_user_manage_can_delete_token_without_api_permission_themselves()
174 $viewer = $this->getViewer();
175 $editor = $this->getEditor();
176 $this->giveUserPermissions($editor, ['users-manage']);
178 $this->asAdmin()->post($viewer->getEditUrl('/create-api-token'), $this->testTokenData);
179 $token = ApiToken::query()->latest()->first();
181 $resp = $this->actingAs($editor)->get($viewer->getEditUrl('/api-tokens/' . $token->id));
182 $resp->assertStatus(200);
183 $resp->assertSeeText('Delete Token');
185 $resp = $this->actingAs($editor)->delete($viewer->getEditUrl('/api-tokens/' . $token->id));
186 $resp->assertRedirect($viewer->getEditUrl('#api_tokens'));
187 $this->assertDatabaseMissing('api_tokens', ['id' => $token->id]);