]> BookStack Code Mirror - bookstack/blob - tests/Actions/AuditLogTest.php
987e23a45bd42f917ceb2c741168021e6b5c5b51
[bookstack] / tests / Actions / AuditLogTest.php
1 <?php
2
3 namespace Tests\Actions;
4
5 use BookStack\Actions\Activity;
6 use BookStack\Actions\ActivityLogger;
7 use BookStack\Actions\ActivityType;
8 use BookStack\Auth\UserRepo;
9 use BookStack\Entities\Repos\PageRepo;
10 use BookStack\Entities\Tools\TrashCan;
11 use Carbon\Carbon;
12 use Tests\TestCase;
13
14 class AuditLogTest extends TestCase
15 {
16     protected ActivityLogger $activityService;
17
18     protected function setUp(): void
19     {
20         parent::setUp();
21         $this->activityService = app(ActivityLogger::class);
22     }
23
24     public function test_only_accessible_with_right_permissions()
25     {
26         $viewer = $this->getViewer();
27         $this->actingAs($viewer);
28
29         $resp = $this->get('/settings/audit');
30         $this->assertPermissionError($resp);
31
32         $this->giveUserPermissions($viewer, ['settings-manage']);
33         $resp = $this->get('/settings/audit');
34         $this->assertPermissionError($resp);
35
36         $this->giveUserPermissions($viewer, ['users-manage']);
37         $resp = $this->get('/settings/audit');
38         $resp->assertStatus(200);
39         $resp->assertSeeText('Audit Log');
40     }
41
42     public function test_shows_activity()
43     {
44         $admin = $this->getAdmin();
45         $this->actingAs($admin);
46         $page = $this->entities->page();
47         $this->activityService->add(ActivityType::PAGE_CREATE, $page);
48         $activity = Activity::query()->orderBy('id', 'desc')->first();
49
50         $resp = $this->get('settings/audit');
51         $resp->assertSeeText($page->name);
52         $resp->assertSeeText('page_create');
53         $resp->assertSeeText($activity->created_at->toDateTimeString());
54         $this->withHtml($resp)->assertElementContains('.table-user-item', $admin->name);
55     }
56
57     public function test_shows_name_for_deleted_items()
58     {
59         $this->actingAs($this->getAdmin());
60         $page = $this->entities->page();
61         $pageName = $page->name;
62         $this->activityService->add(ActivityType::PAGE_CREATE, $page);
63
64         app(PageRepo::class)->destroy($page);
65         app(TrashCan::class)->empty();
66
67         $resp = $this->get('settings/audit');
68         $resp->assertSeeText('Deleted Item');
69         $resp->assertSeeText('Name: ' . $pageName);
70     }
71
72     public function test_shows_activity_for_deleted_users()
73     {
74         $viewer = $this->getViewer();
75         $this->actingAs($viewer);
76         $page = $this->entities->page();
77         $this->activityService->add(ActivityType::PAGE_CREATE, $page);
78
79         $this->actingAs($this->getAdmin());
80         app(UserRepo::class)->destroy($viewer);
81
82         $resp = $this->get('settings/audit');
83         $resp->assertSeeText("[ID: {$viewer->id}] Deleted User");
84     }
85
86     public function test_filters_by_key()
87     {
88         $this->actingAs($this->getAdmin());
89         $page = $this->entities->page();
90         $this->activityService->add(ActivityType::PAGE_CREATE, $page);
91
92         $resp = $this->get('settings/audit');
93         $resp->assertSeeText($page->name);
94
95         $resp = $this->get('settings/audit?event=page_delete');
96         $resp->assertDontSeeText($page->name);
97     }
98
99     public function test_date_filters()
100     {
101         $this->actingAs($this->getAdmin());
102         $page = $this->entities->page();
103         $this->activityService->add(ActivityType::PAGE_CREATE, $page);
104
105         $yesterday = (Carbon::now()->subDay()->format('Y-m-d'));
106         $tomorrow = (Carbon::now()->addDay()->format('Y-m-d'));
107
108         $resp = $this->get('settings/audit?date_from=' . $yesterday);
109         $resp->assertSeeText($page->name);
110
111         $resp = $this->get('settings/audit?date_from=' . $tomorrow);
112         $resp->assertDontSeeText($page->name);
113
114         $resp = $this->get('settings/audit?date_to=' . $tomorrow);
115         $resp->assertSeeText($page->name);
116
117         $resp = $this->get('settings/audit?date_to=' . $yesterday);
118         $resp->assertDontSeeText($page->name);
119     }
120
121     public function test_user_filter()
122     {
123         $admin = $this->getAdmin();
124         $editor = $this->getEditor();
125         $this->actingAs($admin);
126         $page = $this->entities->page();
127         $this->activityService->add(ActivityType::PAGE_CREATE, $page);
128
129         $this->actingAs($editor);
130         $chapter = $this->entities->chapter();
131         $this->activityService->add(ActivityType::CHAPTER_UPDATE, $chapter);
132
133         $resp = $this->actingAs($admin)->get('settings/audit?user=' . $admin->id);
134         $resp->assertSeeText($page->name);
135         $resp->assertDontSeeText($chapter->name);
136
137         $resp = $this->actingAs($admin)->get('settings/audit?user=' . $editor->id);
138         $resp->assertSeeText($chapter->name);
139         $resp->assertDontSeeText($page->name);
140     }
141
142     public function test_ip_address_logged_and_visible()
143     {
144         config()->set('app.proxies', '*');
145         $editor = $this->getEditor();
146         $page = $this->entities->page();
147
148         $this->actingAs($editor)->put($page->getUrl(), [
149             'name' => 'Updated page',
150             'html' => '<p>Updated content</p>',
151         ], [
152             'X-Forwarded-For' => '192.123.45.1',
153         ])->assertRedirect($page->refresh()->getUrl());
154
155         $this->assertDatabaseHas('activities', [
156             'type'      => ActivityType::PAGE_UPDATE,
157             'ip'        => '192.123.45.1',
158             'user_id'   => $editor->id,
159             'entity_id' => $page->id,
160         ]);
161
162         $resp = $this->asAdmin()->get('/settings/audit');
163         $resp->assertSee('192.123.45.1');
164     }
165
166     public function test_ip_address_is_searchable()
167     {
168         config()->set('app.proxies', '*');
169         $editor = $this->getEditor();
170         $page = $this->entities->page();
171
172         $this->actingAs($editor)->put($page->getUrl(), [
173             'name' => 'Updated page',
174             'html' => '<p>Updated content</p>',
175         ], [
176             'X-Forwarded-For' => '192.123.45.1',
177         ])->assertRedirect($page->refresh()->getUrl());
178
179         $this->actingAs($editor)->put($page->getUrl(), [
180             'name' => 'Updated page',
181             'html' => '<p>Updated content</p>',
182         ], [
183             'X-Forwarded-For' => '192.122.45.1',
184         ])->assertRedirect($page->refresh()->getUrl());
185
186         $resp = $this->asAdmin()->get('/settings/audit?&ip=192.123');
187         $resp->assertSee('192.123.45.1');
188         $resp->assertDontSee('192.122.45.1');
189     }
190
191     public function test_ip_address_not_logged_in_demo_mode()
192     {
193         config()->set('app.proxies', '*');
194         config()->set('app.env', 'demo');
195         $editor = $this->getEditor();
196         $page = $this->entities->page();
197
198         $this->actingAs($editor)->put($page->getUrl(), [
199             'name' => 'Updated page',
200             'html' => '<p>Updated content</p>',
201         ], [
202             'X-Forwarded-For' => '192.123.45.1',
203             'REMOTE_ADDR'     => '192.123.45.2',
204         ])->assertRedirect($page->refresh()->getUrl());
205
206         $this->assertDatabaseHas('activities', [
207             'type'      => ActivityType::PAGE_UPDATE,
208             'ip'        => '127.0.0.1',
209             'user_id'   => $editor->id,
210             'entity_id' => $page->id,
211         ]);
212     }
213
214     public function test_ip_address_respects_precision_setting()
215     {
216         config()->set('app.proxies', '*');
217         config()->set('app.ip_address_precision', 2);
218         $editor = $this->getEditor();
219         $page = $this->entities->page();
220
221         $this->actingAs($editor)->put($page->getUrl(), [
222             'name' => 'Updated page',
223             'html' => '<p>Updated content</p>',
224         ], [
225             'X-Forwarded-For' => '192.123.45.1',
226         ])->assertRedirect($page->refresh()->getUrl());
227
228         $this->assertDatabaseHas('activities', [
229             'type'      => ActivityType::PAGE_UPDATE,
230             'ip'        => '192.123.x.x',
231             'user_id'   => $editor->id,
232             'entity_id' => $page->id,
233         ]);
234     }
235 }