1 <?php namespace Tests\User;
3 use BookStack\Actions\ActivityType;
4 use BookStack\Api\ApiToken;
8 class UserApiTokenTest extends TestCase
11 protected $testTokenData = [
12 'name' => 'My test API token',
13 'expires_at' => '2050-04-01',
16 public function test_tokens_section_not_visible_without_access_api_permission()
18 $user = $this->getViewer();
20 $resp = $this->actingAs($user)->get($user->getEditUrl());
21 $resp->assertDontSeeText('API Tokens');
23 $this->giveUserPermissions($user, ['access-api']);
25 $resp = $this->actingAs($user)->get($user->getEditUrl());
26 $resp->assertSeeText('API Tokens');
27 $resp->assertSeeText('Create Token');
30 public function test_those_with_manage_users_can_view_other_user_tokens_but_not_create()
32 $viewer = $this->getViewer();
33 $editor = $this->getEditor();
34 $this->giveUserPermissions($viewer, ['users-manage']);
36 $resp = $this->actingAs($viewer)->get($editor->getEditUrl());
37 $resp->assertSeeText('API Tokens');
38 $resp->assertDontSeeText('Create Token');
41 public function test_create_api_token()
43 $editor = $this->getEditor();
45 $resp = $this->asAdmin()->get($editor->getEditUrl('/create-api-token'));
46 $resp->assertStatus(200);
47 $resp->assertSee('Create API Token');
48 $resp->assertSee('Token Secret');
50 $resp = $this->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
51 $token = ApiToken::query()->latest()->first();
52 $resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id));
53 $this->assertDatabaseHas('api_tokens', [
54 'user_id' => $editor->id,
55 'name' => $this->testTokenData['name'],
56 'expires_at' => $this->testTokenData['expires_at'],
60 $this->assertSessionHas('api-token-secret:' . $token->id);
61 $secret = session('api-token-secret:' . $token->id);
62 $this->assertDatabaseMissing('api_tokens', [
65 $this->assertTrue(\Hash::check($secret, $token->secret));
67 $this->assertTrue(strlen($token->token_id) === 32);
68 $this->assertTrue(strlen($secret) === 32);
70 $this->assertSessionHas('success');
71 $this->assertActivityExists(ActivityType::API_TOKEN_CREATE);
74 public function test_create_with_no_expiry_sets_expiry_hundred_years_away()
76 $editor = $this->getEditor();
77 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), ['name' => 'No expiry token', 'expires_at' => '']);
78 $token = ApiToken::query()->latest()->first();
80 $over = Carbon::now()->addYears(101);
81 $under = Carbon::now()->addYears(99);
83 ($token->expires_at < $over && $token->expires_at > $under),
84 "Token expiry set at 100 years in future"
88 public function test_created_token_displays_on_profile_page()
90 $editor = $this->getEditor();
91 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
92 $token = ApiToken::query()->latest()->first();
94 $resp = $this->get($editor->getEditUrl());
95 $resp->assertElementExists('#api_tokens');
96 $resp->assertElementContains('#api_tokens', $token->name);
97 $resp->assertElementContains('#api_tokens', $token->token_id);
98 $resp->assertElementContains('#api_tokens', $token->expires_at->format('Y-m-d'));
101 public function test_secret_shown_once_after_creation()
103 $editor = $this->getEditor();
104 $resp = $this->asAdmin()->followingRedirects()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
105 $resp->assertSeeText('Token Secret');
107 $token = ApiToken::query()->latest()->first();
108 $this->assertNull(session('api-token-secret:' . $token->id));
110 $resp = $this->get($editor->getEditUrl('/api-tokens/' . $token->id));
111 $resp->assertDontSeeText('Client Secret');
114 public function test_token_update()
116 $editor = $this->getEditor();
117 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
118 $token = ApiToken::query()->latest()->first();
120 'name' => 'My updated token',
121 'expires_at' => '2011-01-01',
124 $resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), $updateData);
125 $resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id));
127 $this->assertDatabaseHas('api_tokens', array_merge($updateData, ['id' => $token->id]));
128 $this->assertSessionHas('success');
129 $this->assertActivityExists(ActivityType::API_TOKEN_UPDATE);
132 public function test_token_update_with_blank_expiry_sets_to_hundred_years_away()
134 $editor = $this->getEditor();
135 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
136 $token = ApiToken::query()->latest()->first();
138 $resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), [
139 'name' => 'My updated token',
144 $over = Carbon::now()->addYears(101);
145 $under = Carbon::now()->addYears(99);
147 ($token->expires_at < $over && $token->expires_at > $under),
148 "Token expiry set at 100 years in future"
152 public function test_token_delete()
154 $editor = $this->getEditor();
155 $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData);
156 $token = ApiToken::query()->latest()->first();
158 $tokenUrl = $editor->getEditUrl('/api-tokens/' . $token->id);
160 $resp = $this->get($tokenUrl . '/delete');
161 $resp->assertSeeText('Delete Token');
162 $resp->assertSeeText($token->name);
163 $resp->assertElementExists('form[action="'.$tokenUrl.'"]');
165 $resp = $this->delete($tokenUrl);
166 $resp->assertRedirect($editor->getEditUrl('#api_tokens'));
167 $this->assertDatabaseMissing('api_tokens', ['id' => $token->id]);
168 $this->assertActivityExists(ActivityType::API_TOKEN_DELETE);
171 public function test_user_manage_can_delete_token_without_api_permission_themselves()
173 $viewer = $this->getViewer();
174 $editor = $this->getEditor();
175 $this->giveUserPermissions($editor, ['users-manage']);
177 $this->asAdmin()->post($viewer->getEditUrl('/create-api-token'), $this->testTokenData);
178 $token = ApiToken::query()->latest()->first();
180 $resp = $this->actingAs($editor)->get($viewer->getEditUrl('/api-tokens/' . $token->id));
181 $resp->assertStatus(200);
182 $resp->assertSeeText('Delete Token');
184 $resp = $this->actingAs($editor)->delete($viewer->getEditUrl('/api-tokens/' . $token->id));
185 $resp->assertRedirect($viewer->getEditUrl('#api_tokens'));
186 $this->assertDatabaseMissing('api_tokens', ['id' => $token->id]);