blob: f83bd2ad24a7caa87f5968eed9e4524501bd03c8 [file] [log] [blame]
Akron33f5c672019-06-24 19:40:47 +02001use Mojo::Base -strict;
2use Test::More;
Akron6a228db2021-10-14 15:57:00 +02003use Mojo::ByteStream 'b';
Akroncdfd9d52019-07-23 11:35:00 +02004use Test::Mojo::WithRoles 'Session';
Akron66ef3b52022-11-22 14:25:15 +01005use Mojo::File qw/path tempfile/;
Akron33f5c672019-06-24 19:40:47 +02006use Data::Dumper;
7
Akron33f5c672019-06-24 19:40:47 +02008#####################
9# Start Fake server #
10#####################
Akron63d963b2019-07-05 15:35:51 +020011my $mount_point = '/realapi/';
Akron33f5c672019-06-24 19:40:47 +020012$ENV{KALAMAR_API} = $mount_point;
13
Akroncdfd9d52019-07-23 11:35:00 +020014my $t = Test::Mojo::WithRoles->new('Kalamar' => {
Akron33f5c672019-06-24 19:40:47 +020015 Kalamar => {
16 plugins => ['Auth']
17 },
18 'Kalamar-Auth' => {
19 client_id => 2,
20 client_secret => 'k414m4r-s3cr3t',
Akron59992122019-10-29 11:28:45 +010021 oauth2 => 1,
22 experimental_client_registration => 1
Akron33f5c672019-06-24 19:40:47 +020023 }
24});
25
26# Mount fake backend
27# Get the fixture path
28my $fixtures_path = path(Mojo::File->new(__FILE__)->dirname, '..', 'server');
29my $fake_backend = $t->app->plugin(
30 Mount => {
31 $mount_point =>
32 $fixtures_path->child('mock.pl')
33 }
34);
35# Configure fake backend
Akroncdfd9d52019-07-23 11:35:00 +020036my $fake_backend_app = $fake_backend->pattern->defaults->{app};
37
38# Set general app logger for simplicity
39$fake_backend_app->log($t->app->log);
40
41my $access_token = $fake_backend_app->get_token('access_token');
42my $refresh_token = $fake_backend_app->get_token('refresh_token');
43my $access_token_2 = $fake_backend_app->get_token('access_token_2');
44my $refresh_token_2 = $fake_backend_app->get_token('refresh_token_2');
45
46# Some routes to modify the session
47# This expires the session
48$t->app->routes->get('/x/expire')->to(
49 cb => sub {
50 my $c = shift;
51 $c->session(auth_exp => 0);
52 return $c->render(text => 'okay')
53 }
54);
55
56# This expires the session and removes the refresh token
57$t->app->routes->get('/x/expire-no-refresh')->to(
58 cb => sub {
59 my $c = shift;
60 $c->session(auth_exp => 0);
61 delete $c->session->{auth_r};
62 return $c->render(text => 'okay')
63 }
64);
65
66# This sets an invalid token
67$t->app->routes->get('/x/invalid')->to(
68 cb => sub {
69 my $c = shift;
70 $c->session(auth_exp => time + 1000);
71 $c->session(auth_r => $refresh_token_2);
72 $c->session(auth => 'Bearer inv4lid');
73 return $c->render(text => 'okay')
74 }
75);
76
77
78# This sets an invalid token
79$t->app->routes->get('/x/invalid-no-refresh')->to(
80 cb => sub {
81 my $c = shift;
82 $c->session(auth_exp => time + 1000);
83 delete $c->session->{auth_r};
84 $c->session(auth => 'Bearer inv4lid');
85 return $c->render(text => 'okay')
86 }
87);
88
89# This sets an invalid refresh token
90$t->app->routes->get('/x/expired-with-wrong-refresh')->to(
91 cb => sub {
92 my $c = shift;
93 $c->session(auth_exp => 0);
94 $c->session(auth => 'Bearer inv4lid');
95 $c->session(auth_r => 'inv4lid');
96 return $c->render(text => 'okay')
97 }
98);
99
Akronbc6b3f22021-01-13 14:53:12 +0100100my $q = qr!(?:\"|")!;
Akron33f5c672019-06-24 19:40:47 +0200101
Akron63d963b2019-07-05 15:35:51 +0200102$t->get_ok('/realapi/v1.0')
Akron33f5c672019-06-24 19:40:47 +0200103 ->status_is(200)
Akronb9070eb2025-12-16 12:17:59 +0100104 ->content_is('Fake server available: 1.0');
Akron33f5c672019-06-24 19:40:47 +0200105
106$t->get_ok('/?q=Baum')
107 ->status_is(200)
108 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
109 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100110 ->content_like(qr/${q}authorized${q}:null/)
Akron33f5c672019-06-24 19:40:47 +0200111 ->element_exists_not('div.button.top a')
112 ->element_exists_not('aside.active')
Akron4d17d0f2025-03-05 20:58:44 +0100113 ->element_exists('aside.off')
Akron33f5c672019-06-24 19:40:47 +0200114 ;
115
116$t->get_ok('/')
117 ->status_is(200)
Akron9fa7cc52022-05-12 11:17:20 +0200118 ->element_exists('form[action=/user/login] input[name=handle_or_email]')
Akronbb3da4d2025-12-05 22:47:35 +0100119 ->element_exists('*[data-testid=handle-or-email]')
120 ->element_exists('*[data-testid=pwd]')
121 ->element_exists('*[data-testid=login-submit]')
122 ->element_exists_not('*[data-testid=logout]')
Uyen-Nhu Tran243fe732024-04-10 01:17:24 +0200123 ->element_exists('aside')
124 ->element_exists('aside.invisible')
Akron33f5c672019-06-24 19:40:47 +0200125 ;
126
Akronff088112021-06-15 15:26:04 +0200127$t->get_ok('/settings/oauth')
128 ->status_is(401)
129 ->text_is('p.no-results', 'Not authenticated')
Akronbb3da4d2025-12-05 22:47:35 +0100130 ->text_is('*[data-testid=error-message]','Not authenticated')
Akronff088112021-06-15 15:26:04 +0200131 ;
132
Helge278fbca2022-11-29 18:49:15 +0100133$t->get_ok('/settings/marketplace')
134 ->status_is(401)
135 ->text_is('p.no-results', 'Not authenticated')
136 ;
137
Akron3e0fdc12020-05-15 16:17:21 +0200138# Test for bug with long password
139$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200140 handle_or_email => 'test',
Akron3e0fdc12020-05-15 16:17:21 +0200141 pwd => 'kjskjhndkjndqknaskjnakjdnkjdankajdnkjdsankjdsakjdfkjahzroiuqzriudjoijdmlamdlkmdsalkmdl' })
142 ->status_is(302)
143 ->header_is('Location' => '/');
144
Akron9fa7cc52022-05-12 11:17:20 +0200145$t->post_ok('/user/login' => form => { handle_or_email => 'test', pwd => 'fail' })
Akron33f5c672019-06-24 19:40:47 +0200146 ->status_is(302)
147 ->header_is('Location' => '/');
148
149$t->get_ok('/')
150 ->status_is(200)
151 ->element_exists('div.notify-error')
152 ->text_is('div.notify-error', 'Bad CSRF token')
Akron9fa7cc52022-05-12 11:17:20 +0200153 ->element_exists('input[name=handle_or_email][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200154 ->element_exists_not('div.button.top a')
155 ;
156
Akron9fa7cc52022-05-12 11:17:20 +0200157$t->post_ok('/user/login' => form => { handle_or_email => 'test', pwd => 'pass' })
Akron33f5c672019-06-24 19:40:47 +0200158 ->status_is(302)
159 ->header_is('Location' => '/');
160
161my $csrf = $t->get_ok('/')
162 ->status_is(200)
163 ->element_exists('div.notify-error')
164 ->text_is('div.notify-error', 'Bad CSRF token')
165 ->element_exists_not('div.button.top a')
166 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
167 ;
168
169$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200170 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200171 pwd => 'ldaperr',
172 csrf_token => $csrf
173})
174 ->status_is(302)
175 ->content_is('')
176 ->header_is('Location' => '/');
177
178$csrf = $t->get_ok('/')
179 ->status_is(200)
180 ->element_exists('div.notify-error')
181 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
Akron9fa7cc52022-05-12 11:17:20 +0200182 ->element_exists('input[name=handle_or_email][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200183 ->element_exists_not('div.button.top a')
Akron3b3c7af2020-05-15 16:23:55 +0200184 ->element_exists_not('div.notify-success')
Akron33f5c672019-06-24 19:40:47 +0200185 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
186 ;
187
188$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200189 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200190 pwd => 'unknown',
191 csrf_token => $csrf
192})
193 ->status_is(302)
194 ->content_is('')
195 ->header_is('Location' => '/');
196
197$csrf = $t->get_ok('/')
198 ->status_is(200)
199 ->element_exists('div.notify-error')
Akron8bbbecf2019-07-01 18:57:30 +0200200 ->text_is('div.notify-error', '2022: LDAP Authentication failed due to unknown user or password!')
Akron9fa7cc52022-05-12 11:17:20 +0200201 ->element_exists('input[name=handle_or_email][value=test]')
Akron33f5c672019-06-24 19:40:47 +0200202 ->element_exists_not('div.button.top a')
203 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
204 ;
205
206$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200207 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200208 pwd => 'pass',
209 csrf_token => $csrf
210})
211 ->status_is(302)
212 ->content_is('')
213 ->header_is('Location' => '/');
214
215$t->get_ok('/')
216 ->status_is(200)
217 ->element_exists_not('div.notify-error')
218 ->element_exists('div.notify-success')
219 ->text_is('div.notify-success', 'Login successful')
Akron1d09b532021-06-15 18:18:25 +0200220 ->element_exists_not('aside.off')
Akrondc0b3ab2021-06-18 11:52:43 +0200221 ->element_exists_not('aside.active')
Akron1d09b532021-06-15 18:18:25 +0200222 ->element_exists('aside.settings')
Akron33f5c672019-06-24 19:40:47 +0200223 ;
224
Akron33f5c672019-06-24 19:40:47 +0200225# Now the user is logged in and should be able to
226# search with authorization
227$t->get_ok('/?q=Baum')
228 ->status_is(200)
Akron4cefe1f2019-09-04 10:11:28 +0200229 ->session_has('/auth')
230 ->session_is('/auth', 'Bearer ' . $access_token)
231 ->session_is('/auth_r', $refresh_token)
232 ->session_is('/user', 'test')
Akron33f5c672019-06-24 19:40:47 +0200233 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
234 ->text_like('#total-results', qr/\d+$/)
235 ->element_exists_not('div.notify-error')
Akronbc6b3f22021-01-13 14:53:12 +0100236 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Uyen-Nhu Tran243fe732024-04-10 01:17:24 +0200237 ->element_exists('nav.dropdown')
Akronbb3da4d2025-12-05 22:47:35 +0100238 ->element_exists_not('*[data-testid=handle-or-email]')
239 ->element_exists('*[data-testid=logout]')
Uyen-Nhu Tran243fe732024-04-10 01:17:24 +0200240 ->element_exists('a.dropdown-item.logout[title~="test"]')
Akron33f5c672019-06-24 19:40:47 +0200241 ;
242
Akron27031aa2020-04-28 14:57:10 +0200243$t->get_ok('/?q=Paum')
244 ->status_is(200)
245 ->text_like('h1 span', qr/KorAP: Find .Paum./i)
246 ->text_is('#total-results', '')
Akronbc6b3f22021-01-13 14:53:12 +0100247 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akron27031aa2020-04-28 14:57:10 +0200248 ->element_exists_not('p.hint')
249 ;
250
Akroncce055c2021-07-02 12:18:03 +0200251# Query with error
252$t->get_ok('/?q=error')
253 ->status_is(400)
254 ->text_is('#notifications .notify-error','500: Internal Server Error')
255;
Akron27031aa2020-04-28 14:57:10 +0200256
Akron33f5c672019-06-24 19:40:47 +0200257# Logout
258$t->get_ok('/user/logout')
259 ->status_is(302)
Akron4cefe1f2019-09-04 10:11:28 +0200260 ->session_hasnt('/auth')
261 ->session_hasnt('/auth_r')
262 ->session_hasnt('/user')
Akron33f5c672019-06-24 19:40:47 +0200263 ->header_is('Location' => '/');
264
265$t->get_ok('/')
266 ->status_is(200)
267 ->element_exists_not('div.notify-error')
268 ->element_exists('div.notify-success')
269 ->text_is('div.notify-success', 'Logout successful')
Akron9fa7cc52022-05-12 11:17:20 +0200270 ->element_exists("input[name=handle_or_email]")
271 ->element_exists("input[name=handle_or_email][value=test]")
Akron33f5c672019-06-24 19:40:47 +0200272 ;
273
274$t->get_ok('/?q=Baum')
275 ->status_is(200)
276 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
277 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100278 ->content_like(qr/${q}authorized${q}:null/)
Akron33f5c672019-06-24 19:40:47 +0200279 ;
280
Akron27031aa2020-04-28 14:57:10 +0200281$t->get_ok('/?q=Paum')
282 ->status_is(200)
283 ->text_like('h1 span', qr/KorAP: Find .Paum./i)
284 ->text_is('#total-results', '')
Akronbc6b3f22021-01-13 14:53:12 +0100285 ->content_like(qr/${q}authorized${q}:null/)
Akron27031aa2020-04-28 14:57:10 +0200286 ->text_is('p.hint', 'Maybe you need to log in first?')
287 ;
288
289
Akron33f5c672019-06-24 19:40:47 +0200290# Get redirect
291my $fwd = $t->get_ok('/?q=Baum&ql=poliqarp')
292 ->status_is(200)
293 ->element_exists_not('div.notify-error')
294 ->tx->res->dom->at('input[name=fwd]')->attr('value')
295 ;
296
297is($fwd, '/?q=Baum&ql=poliqarp', 'Redirect is valid');
298
299$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200300 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200301 pwd => 'pass',
302 csrf_token => $csrf,
303 fwd => 'http://bad.example.com/test'
304})
305 ->status_is(302)
306 ->header_is('Location' => '/');
307
308$t->get_ok('/')
309 ->status_is(200)
310 ->element_exists('div.notify-error')
311 ->element_exists_not('div.notify-success')
312 ->text_is('div.notify-error', 'Redirect failure')
313 ;
314
315$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200316 handle_or_email => 'test',
Akron33f5c672019-06-24 19:40:47 +0200317 pwd => 'pass',
318 csrf_token => $csrf,
319 fwd => $fwd
320})
321 ->status_is(302)
322 ->header_is('Location' => '/?q=Baum&ql=poliqarp');
323
Akron8bbbecf2019-07-01 18:57:30 +0200324$t->get_ok('/?q=Baum&ql=poliqarp')
325 ->status_is(200)
326 ->element_exists_not('div.notify-error')
327 ->element_exists('div.notify-success')
328 ->text_is('div.notify-success', 'Login successful')
Akroncdfd9d52019-07-23 11:35:00 +0200329 ->session_has('/auth')
330 ->session_is('/auth', 'Bearer ' . $access_token)
331 ->session_is('/auth_r', $refresh_token)
332 ->header_isnt('X-Kalamar-Cache', 'true')
Akron8bbbecf2019-07-01 18:57:30 +0200333 ;
334
Akroncdfd9d52019-07-23 11:35:00 +0200335# Expire the session
336# (makes the token be marked as expired - though it isn't serverside)
337$t->get_ok('/x/expire')
Akron8bbbecf2019-07-01 18:57:30 +0200338 ->status_is(200)
Akroncdfd9d52019-07-23 11:35:00 +0200339 ->content_is('okay')
340 ;
341
342## It may be a problem, but the cache is still valid
343$t->get_ok('/?q=Baum')
344 ->status_is(200)
345 ->text_like('h1 span', qr/KorAP: Find .Baum./i)
346 ->text_like('#total-results', qr/\d+$/)
Akronbc6b3f22021-01-13 14:53:12 +0100347 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200348 ->header_is('X-Kalamar-Cache', 'true')
349 ;
350
351# Query without partial cache (unfortunately) (but no total results)
Akron58c60992021-09-07 13:11:43 +0200352my $err = $t->get_ok('/?q=baum&cutoff=true')
Akroncdfd9d52019-07-23 11:35:00 +0200353 ->status_is(200)
354 ->session_is('/auth', 'Bearer ' . $access_token_2)
355 ->session_is('/auth_r', $refresh_token_2)
Akroncdfd9d52019-07-23 11:35:00 +0200356 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
357 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
358 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100359 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200360 ->header_isnt('X-Kalamar-Cache', 'true')
Akronbc6b3f22021-01-13 14:53:12 +0100361 ->content_like(qr!${q}cutOff${q}:true!)
Akroncdfd9d52019-07-23 11:35:00 +0200362 ->element_exists_not('#total-results')
Akron58c60992021-09-07 13:11:43 +0200363 ->tx->res->dom->at('#error')
Akroncdfd9d52019-07-23 11:35:00 +0200364 ;
Akron58c60992021-09-07 13:11:43 +0200365is(defined $err ? $err->text : '', '');
Akroncdfd9d52019-07-23 11:35:00 +0200366
367# Expire the session and remove the refresh option
368$t->get_ok('/x/expire-no-refresh')
369 ->status_is(200)
370 ->content_is('okay')
371 ;
372
373$t->app->defaults(no_cache => 1);
374
375
376$t->get_ok('/x/invalid-no-refresh')
377 ->status_is(200)
378 ->content_is('okay')
379 ;
380
381# Query without cache
382# The token is invalid and can't be refreshed!
Akron58c60992021-09-07 13:11:43 +0200383$err = $t->get_ok('/?q=baum&cutoff=true')
Akron3c390c42020-03-30 09:06:21 +0200384 ->status_is(400)
Akroncdfd9d52019-07-23 11:35:00 +0200385 ->session_hasnt('/auth')
386 ->session_hasnt('/auth_r')
Akroncdfd9d52019-07-23 11:35:00 +0200387 ->text_is('div.notify-error','Access token invalid')
388 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
389 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
390 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100391 ->content_unlike(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200392 ->header_isnt('X-Kalamar-Cache', 'true')
393 ->element_exists('p.no-results')
Akron58c60992021-09-07 13:11:43 +0200394 ->tx->res->dom->at('#error')
Akroncdfd9d52019-07-23 11:35:00 +0200395 ;
Akron58c60992021-09-07 13:11:43 +0200396is(defined $err ? $err->text : '', '');
397
Akroncdfd9d52019-07-23 11:35:00 +0200398
399$t->get_ok('/x/invalid')
400 ->status_is(200)
401 ->content_is('okay')
402 ;
403
404# Query without cache
405# The token is invalid and can't be refreshed!
Akron58c60992021-09-07 13:11:43 +0200406$err = $t->get_ok('/?q=baum&cutoff=true')
Akroncdfd9d52019-07-23 11:35:00 +0200407 ->status_is(200)
408 ->session_is('/auth', 'Bearer ' . $access_token_2)
409 ->session_is('/auth_r', $refresh_token_2)
Akroncdfd9d52019-07-23 11:35:00 +0200410 ->element_exists_not('div.notify-error','Access token invalid')
411 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
412 ->element_exists('meta[name="DC.title"][content="KorAP: Find »baum« with Poliqarp"]')
413 ->element_exists('body[itemscope][itemtype="http://schema.org/SearchResultsPage"]')
Akronbc6b3f22021-01-13 14:53:12 +0100414 ->content_like(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200415 ->header_isnt('X-Kalamar-Cache', 'true')
416 ->element_exists_not('p.no-results')
Akron58c60992021-09-07 13:11:43 +0200417 ->tx->res->dom->at('#error')
Akron8bbbecf2019-07-01 18:57:30 +0200418 ;
Akron58c60992021-09-07 13:11:43 +0200419is(defined $err ? $err->text : '', '');
Akron8bbbecf2019-07-01 18:57:30 +0200420
Akron33f5c672019-06-24 19:40:47 +0200421
Akroncdfd9d52019-07-23 11:35:00 +0200422$t->get_ok('/x/expired-with-wrong-refresh')
423 ->status_is(200)
424 ->content_is('okay')
425 ;
Akron4796e002019-07-05 10:13:15 +0200426
Akron4796e002019-07-05 10:13:15 +0200427
Akroncdfd9d52019-07-23 11:35:00 +0200428# The token is invalid and can't be refreshed!
Akron58c60992021-09-07 13:11:43 +0200429my $dom = $t->get_ok('/?q=baum&cutoff=true')
Akron3c390c42020-03-30 09:06:21 +0200430 ->status_is(400)
Akroncdfd9d52019-07-23 11:35:00 +0200431 ->session_hasnt('/auth')
432 ->session_hasnt('/auth_r')
Akroncdfd9d52019-07-23 11:35:00 +0200433 ->text_is('div.notify-error','Refresh token is expired')
434 ->text_is('title', 'KorAP: Find »baum« with Poliqarp')
Akronbc6b3f22021-01-13 14:53:12 +0100435 ->content_unlike(qr/${q}authorized${q}:${q}yes${q}/)
Akroncdfd9d52019-07-23 11:35:00 +0200436 ->element_exists('p.no-results')
Akron58c60992021-09-07 13:11:43 +0200437 ->tx->res->dom;
438
439$csrf = $dom->at('input[name="csrf_token"]')
Akron59992122019-10-29 11:28:45 +0100440 ->attr('value')
Akroncdfd9d52019-07-23 11:35:00 +0200441 ;
Akron4796e002019-07-05 10:13:15 +0200442
Akron58c60992021-09-07 13:11:43 +0200443$err = $dom->at('#error');
444is(defined $err ? $err->text : '', '');
445
446
Akron6a228db2021-10-14 15:57:00 +0200447# This should fail
448my $wide_char_login = "\x{61}\x{E5}\x{61}"; # "\x{443}\x{434}";
Akron59992122019-10-29 11:28:45 +0100449$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200450 handle_or_email => $wide_char_login,
Akron6a228db2021-10-14 15:57:00 +0200451 pwd => 'pass',
452 csrf_token => $csrf,
453 fwd => $fwd
454})
455 ->status_is(302)
456 ->header_is('Location' => '/');
457
458$t->get_ok('/')
459 ->status_is(200)
460 ->element_exists('div.notify-error')
461 ->text_is('div.notify-error', 'Invalid character in request')
Akron9fa7cc52022-05-12 11:17:20 +0200462 ->element_exists('input[name=handle_or_email]:not([value])')
Akron6a228db2021-10-14 15:57:00 +0200463 ->element_exists_not('div.button.top a')
464 ;
465
466# Login:
467# UTF8 request
468my $username = b('täst')->encode;
469$t->post_ok('/user/login' => form => {
Akron9fa7cc52022-05-12 11:17:20 +0200470 handle_or_email => $username,
Akron59992122019-10-29 11:28:45 +0100471 pwd => 'pass',
472 csrf_token => $csrf
473})
474 ->status_is(302)
475 ->content_is('')
476 ->header_is('Location' => '/');
477
478$t->get_ok('/')
479 ->status_is(200)
Akron78e0b6f2023-04-12 12:50:29 +0200480 ->content_type_is('text/html;charset=UTF-8')
Akron59992122019-10-29 11:28:45 +0100481 ->element_exists_not('div.notify-error')
482 ->element_exists('div.notify-success')
483 ->text_is('div.notify-success', 'Login successful')
Akron78e0b6f2023-04-12 12:50:29 +0200484 # Weird error in certain environments otherwise
485 ->attr_like('a.logout', 'title', qr!^Logout: t.+st$!)
Akron1d09b532021-06-15 18:18:25 +0200486 ->element_exists_not('aside.off')
Akrondc0b3ab2021-06-18 11:52:43 +0200487 ->element_exists_not('aside.active')
Akron1d09b532021-06-15 18:18:25 +0200488 ->element_exists('aside.settings')
Akronb0a7a0f2025-02-27 09:51:06 +0100489 ->text_is('nav.dropdown a:first-child span','API tokens')
Akron59992122019-10-29 11:28:45 +0100490 ;
491
Uyen-Nhu Tran94f93b02024-11-20 20:17:57 +0100492
Akron59992122019-10-29 11:28:45 +0100493$t->get_ok('/settings/oauth')
494 ->text_is('form.form-table legend', 'Register new client application')
495 ->attr_is('form.oauth-register','action', '/settings/oauth/register')
Akron9f2ad342022-05-04 16:16:40 +0200496 ->text_is('label[for=name]','Name of the client application')
497 ->text_is('label[for=type]','Type of the client application')
498 ->text_is('label[for=desc]','Short description')
Helge9f9d4852024-12-09 16:06:34 +0100499 ->text_like('label[for=url]'=> '/Homepage/')
500 ->element_exists('label[for=url] > span.field-required')
Akron9f2ad342022-05-04 16:16:40 +0200501 ->text_is('label[for=redirect_uri]','Redirect URI')
502 ->text_is('label[for=src]','Declaration of the plugin (*.json file)')
Akron1a9d5be2020-03-19 17:28:33 +0100503 ->element_exists('ul.client-list')
504 ->element_exists_not('ul.client-list > li')
Akronad011bb2021-06-10 12:16:36 +0200505 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
506 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
507 ->header_is('Pragma','no-cache')
Akron59992122019-10-29 11:28:45 +0100508 ;
Akronad011bb2021-06-10 12:16:36 +0200509
Akron83224302026-01-21 12:05:51 +0100510
511my $log_output = '';
512open my $log_fh, '>', \$log_output or die $!;
513$t->app->log->handle($log_fh);
514$t->app->log->level('warn');
Helge278fbca2022-11-29 18:49:15 +0100515
516$t->get_ok('/settings/marketplace')
517 ->status_is(200)
518 ->text_is('html head title' => 'Marketplace')
Helgedb720ea2023-03-20 09:39:36 +0100519 ->element_exists_not('ul.plugin_list')
520 ->element_exists_not('ul.plugin_in-list')
Helge278fbca2022-11-29 18:49:15 +0100521 ;
522
Akron83224302026-01-21 12:05:51 +0100523is($log_output, '', 'Check log is fine');
Helgedb720ea2023-03-20 09:39:36 +0100524
Akron59992122019-10-29 11:28:45 +0100525$csrf = $t->post_ok('/settings/oauth/register' => form => {
526 name => 'MyApp',
527 type => 'PUBLIC',
Akron6b75d122022-05-12 17:39:05 +0200528 desc => 'This is my plugin application'
Akron59992122019-10-29 11:28:45 +0100529})
530 ->text_is('div.notify-error', 'Bad CSRF token')
531 ->tx->res->dom->at('input[name="csrf_token"]')
532 ->attr('value')
533 ;
534
535$t->post_ok('/settings/oauth/register' => form => {
536 name => 'MyApp',
Akron99968a92022-06-03 12:32:07 +0200537 type => 'PUBLIC',
Akron6b75d122022-05-12 17:39:05 +0200538 desc => 'This is my plugin application',
Akron9f2ad342022-05-04 16:16:40 +0200539 csrf_token => $csrf,
540 src => {
541 filename => '',
542 content => ''
543 }
Akron59992122019-10-29 11:28:45 +0100544})
545 ->status_is(200)
546 ->element_exists('div.notify-success')
547 ->text_is('legend', 'Client Credentials')
548 ->text_is('label[for=client_id]', 'ID of the client application')
549 ->element_exists('input[name=client_id][readonly][value]')
Akron99968a92022-06-03 12:32:07 +0200550 ->element_exists_not('input[name=client_secret][readonly][value]')
Akronad011bb2021-06-10 12:16:36 +0200551 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
552 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
553 ->header_is('Pragma','no-cache')
Akron59992122019-10-29 11:28:45 +0100554 ;
Akron4796e002019-07-05 10:13:15 +0200555
Akron58c60992021-09-07 13:11:43 +0200556my $anchor = $t->get_ok('/settings/oauth')
Akronc1aaf932021-06-09 12:19:15 +0200557 ->text_is('.form-table legend', 'Register new client application')
558 ->attr_is('.oauth-register','action', '/settings/oauth/register')
Akron17de86e2020-04-16 16:03:40 +0200559 ->text_is('ul.client-list > li > span.client-name a', 'MyApp')
Akron6b75d122022-05-12 17:39:05 +0200560 ->text_is('ul.client-list > li > p.client-desc', 'This is my plugin application')
Akronad011bb2021-06-10 12:16:36 +0200561 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
562 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
563 ->header_is('Pragma','no-cache')
Akronb6b156e2022-03-31 14:57:49 +0200564 ->tx->res->dom->at('ul.client-list > li > p.client-url a')
Akron17de86e2020-04-16 16:03:40 +0200565 ;
Akron58c60992021-09-07 13:11:43 +0200566is(defined $anchor ? $anchor->text : '', '');
Akron17de86e2020-04-16 16:03:40 +0200567
Akron041ca4d2021-06-10 11:52:51 +0200568$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akron17de86e2020-04-16 16:03:40 +0200569 ->status_is(200)
Akronc1aaf932021-06-09 12:19:15 +0200570 ->text_is('ul.client-list > li.client > span.client-name', 'MyApp')
Akron6b75d122022-05-12 17:39:05 +0200571 ->text_is('ul.client-list > li.client > p.client-desc', 'This is my plugin application')
Akron17de86e2020-04-16 16:03:40 +0200572 ->text_is('a.client-unregister', 'Unregister')
Akron041ca4d2021-06-10 11:52:51 +0200573 ->attr_is('a.client-unregister', 'href', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/unregister?name=MyApp')
Akron1a9d5be2020-03-19 17:28:33 +0100574 ;
575
Akron041ca4d2021-06-10 11:52:51 +0200576$csrf = $t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/unregister?name=MyApp')
Akron1a9d5be2020-03-19 17:28:33 +0100577 ->content_like(qr!Do you really want to unregister \<span class="client-name"\>MyApp\<\/span\>?!)
Akronc1aaf932021-06-09 12:19:15 +0200578 ->attr_is('.form-table input[name=client-name]', 'value', 'MyApp')
Akronad011bb2021-06-10 12:16:36 +0200579 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
580 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
581 ->header_is('Pragma','no-cache')
Akron1a9d5be2020-03-19 17:28:33 +0100582 ->tx->res->dom->at('input[name="csrf_token"]')
583 ->attr('value')
584 ;
585
Akron041ca4d2021-06-10 11:52:51 +0200586$t->post_ok('/settings/oauth/xxxx==/unregister' => form => {
Akron1a9d5be2020-03-19 17:28:33 +0100587 'client-name' => 'MyApp',
Akron1a9d5be2020-03-19 17:28:33 +0100588 'csrf_token' => $csrf
589})->status_is(302)
590 ->content_is('')
591 ->header_is('Location' => '/settings/oauth')
592 ;
593
594$t->get_ok('/settings/oauth')
Akronc1aaf932021-06-09 12:19:15 +0200595 ->text_is('.form-table legend', 'Register new client application')
596 ->attr_is('.oauth-register','action', '/settings/oauth/register')
Akron1a9d5be2020-03-19 17:28:33 +0100597 ->element_exists('ul.client-list > li')
598 ->text_is('div.notify', 'Unknown client with xxxx==.')
Akronad011bb2021-06-10 12:16:36 +0200599 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
600 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
601 ->header_is('Pragma','no-cache')
Akron1a9d5be2020-03-19 17:28:33 +0100602 ;
603
Akron041ca4d2021-06-10 11:52:51 +0200604$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/unregister' => form => {
Akron1a9d5be2020-03-19 17:28:33 +0100605 'client-name' => 'MyApp',
Akron1a9d5be2020-03-19 17:28:33 +0100606 'csrf_token' => $csrf
607})->status_is(302)
608 ->content_is('')
609 ->header_is('Location' => '/settings/oauth')
610 ;
611
612$t->get_ok('/settings/oauth')
Akronc1aaf932021-06-09 12:19:15 +0200613 ->text_is('.form-table legend', 'Register new client application')
614 ->attr_is('.oauth-register','action', '/settings/oauth/register')
Akron1a9d5be2020-03-19 17:28:33 +0100615 ->element_exists_not('ul.client-list > li')
616 ->text_is('div.notify-success', 'Successfully deleted MyApp')
Akronad011bb2021-06-10 12:16:36 +0200617 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
618 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
619 ->header_is('Pragma','no-cache')
Akron1a9d5be2020-03-19 17:28:33 +0100620 ;
621
Akron83209f72021-01-29 17:54:15 +0100622$t->post_ok('/settings/oauth/register' => form => {
623 name => 'MyApp2',
624 type => 'PUBLIC',
Akron6b75d122022-05-12 17:39:05 +0200625 desc => 'This is my plugin application',
Akron83209f72021-01-29 17:54:15 +0100626 csrf_token => $csrf
627})->status_is(200)
628 ->element_exists('div.notify-success')
629 ->text_is('legend', 'Client Credentials')
630 ->text_is('label[for=client_id]', 'ID of the client application')
631 ->element_exists('input[name=client_id][readonly][value]')
632 ->element_exists_not('input[name=client_secret][readonly][value]')
Akronad011bb2021-06-10 12:16:36 +0200633 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
634 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
635 ->header_is('Pragma','no-cache')
Akronb6b156e2022-03-31 14:57:49 +0200636 ->element_exists('.client-issue-token')
Akron83209f72021-01-29 17:54:15 +0100637 ;
638
Akron041ca4d2021-06-10 11:52:51 +0200639$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akron83209f72021-01-29 17:54:15 +0100640 ->text_is('.client-name', 'MyApp2')
Akron6b75d122022-05-12 17:39:05 +0200641 ->text_is('.client-desc', 'This is my plugin application')
Akrone997bb52021-06-11 16:44:06 +0200642 ->text_is('.client-issue-token', 'Issue new token')
Akron041ca4d2021-06-10 11:52:51 +0200643 ->attr_is('.client-issue-token', 'href', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?name=MyApp2')
Akronad011bb2021-06-10 12:16:36 +0200644 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
645 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
646 ->header_is('Pragma','no-cache')
Akrone997bb52021-06-11 16:44:06 +0200647 ->text_is('ul.token-list label[for=token]', 'Access Token')
648 ->text_is('p[name=created]', 'Created at ')
649 ->text_is('p[name=expires]', 'Expires in 31533851 seconds.')
Akronb6b156e2022-03-31 14:57:49 +0200650 ->element_exists('.client-issue-token')
Akron83209f72021-01-29 17:54:15 +0100651 ;
652
Akron041ca4d2021-06-10 11:52:51 +0200653$csrf = $t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?name=MyApp2')
Akron83209f72021-01-29 17:54:15 +0100654 ->status_is(200)
Akron041ca4d2021-06-10 11:52:51 +0200655 ->attr_is('#issue-token','action', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token')
Akron83209f72021-01-29 17:54:15 +0100656 ->attr_is('input[name=client-id]', 'value', 'fCBbQkA2NDA3MzM1Yw==')
657 ->attr_is('input[name=name]', 'value', 'MyApp2')
Akronad011bb2021-06-10 12:16:36 +0200658 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
659 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
660 ->header_is('Pragma','no-cache')
Akrone997bb52021-06-11 16:44:06 +0200661 ->text_is('a.button-abort', 'Abort')
662 ->attr_is('#issue-token input[type=submit]', 'value', 'Issue new token')
663 ->content_like(qr!Issue a new token for!)
Akron83209f72021-01-29 17:54:15 +0100664 ->tx->res->dom->at('input[name="csrf_token"]')
665 ->attr('value')
666 ;
667
Akron041ca4d2021-06-10 11:52:51 +0200668$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token' => form => {
Akron83209f72021-01-29 17:54:15 +0100669 csrf_token => $csrf,
670 name => 'MyApp2',
671 'client-id' => 'fCBbQkA2NDA3MzM1Yw=='
672})
Akronbc94a9c2021-04-15 00:07:35 +0200673 ->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200674 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronbc94a9c2021-04-15 00:07:35 +0200675 ;
676
Akron041ca4d2021-06-10 11:52:51 +0200677$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
678 ->status_is(200)
Akronbc94a9c2021-04-15 00:07:35 +0200679 ->text_is('div.notify-success', 'New access token created')
Akronad011bb2021-06-10 12:16:36 +0200680 ->status_is(200)
681 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
682 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
683 ->header_is('Pragma','no-cache')
Akron83209f72021-01-29 17:54:15 +0100684 ;
685
Akrone3daaeb2023-05-08 09:44:18 +0200686$t->post_ok('/settings/oauth/307/token' => form => {
687 csrf_token => $csrf,
688 name => 'MyApp2',
689})
690 ->status_is(302)
691 ->header_is('Location','/settings/oauth/307')
692 ;
693
694$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
695 ->status_is(200)
696 ->text_is('div.notify-success', 'New access token created')
697 ->status_is(200)
698 ->header_is('Cache-Control','max-age=0, no-cache, no-store, must-revalidate')
699 ->header_is('Expires','Thu, 01 Jan 1970 00:00:00 GMT')
700 ->header_is('Pragma','no-cache')
701 ;
702
703
Akron041ca4d2021-06-10 11:52:51 +0200704$csrf = $t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200705 ->status_is(200)
Akron041ca4d2021-06-10 11:52:51 +0200706 ->attr_is('form.token-revoke', 'action', '/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token/revoke')
Akronc1aaf932021-06-09 12:19:15 +0200707 ->attr_is('form.token-revoke input[name=token]', 'value', 'jhkhkjhk_hjgjsfz67i')
708 ->attr_is('form.token-revoke input[name=name]', 'value', 'MyApp2')
709 ->tx->res->dom->at('input[name="csrf_token"]')
710 ->attr('value')
711 ;
712
Akron041ca4d2021-06-10 11:52:51 +0200713$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token/revoke' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200714 csrf_token => $csrf,
715 name => 'MyApp2',
716 token => 'jhkhkjhk_hjgjsfz67i'
717})
718 ->status_is(200)
Akron041ca4d2021-06-10 11:52:51 +0200719 ->attr_is('form#revoke-token','action','/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE')
Akronc1aaf932021-06-09 12:19:15 +0200720 ->attr_is('form#revoke-token','method','POST')
721 ->attr_is('form#revoke-token input[name=token]','value','jhkhkjhk_hjgjsfz67i')
Akrone997bb52021-06-11 16:44:06 +0200722 ->text_is('a.button-abort', 'Abort')
723 ->attr_is('#revoke-token input[type=submit]', 'value', 'Revoke')
724 ->content_like(qr!Revoke a token for!)
Akronc1aaf932021-06-09 12:19:15 +0200725;
726
727
728# CSRF missing
Akron041ca4d2021-06-10 11:52:51 +0200729$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200730 name => 'MyApp2',
731 token => 'jhkhkjhk_hjgjsfz67i'
732})->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200733 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200734 ;
735
Akron041ca4d2021-06-10 11:52:51 +0200736$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200737 ->element_exists_not('div.notify-success')
738 ->text_is('div.notify-error', 'Bad CSRF token')
739 ;
740
741# Token missing
Akron041ca4d2021-06-10 11:52:51 +0200742$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200743 name => 'MyApp2',
744 csrf_token => $csrf,
745})->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200746 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200747 ;
748
Akron041ca4d2021-06-10 11:52:51 +0200749$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200750 ->element_exists_not('div.notify-success')
751 ->text_is('div.notify-error', 'Some fields are invalid')
752 ;
753
Akron041ca4d2021-06-10 11:52:51 +0200754$t->post_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==/token?_method=DELETE' => form => {
Akronc1aaf932021-06-09 12:19:15 +0200755 name => 'MyApp2',
756 csrf_token => $csrf,
757 token => 'jhkhkjhk_hjgjsfz67i'
758})->status_is(302)
Akron041ca4d2021-06-10 11:52:51 +0200759 ->header_is('Location','/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200760 ;
761
Akron041ca4d2021-06-10 11:52:51 +0200762$t->get_ok('/settings/oauth/fCBbQkA2NDA3MzM1Yw==')
Akronc1aaf932021-06-09 12:19:15 +0200763 ->element_exists_not('div.notify-error')
764 ->text_is('div.notify-success', 'Token was revoked successfully')
765 ;
Akron83209f72021-01-29 17:54:15 +0100766
Akronb6b156e2022-03-31 14:57:49 +0200767$t->app->routes->get('/x/redirect-target')->to(
768 cb => sub {
769 my $c = shift;
770 return $c->render(text => 'redirected');
771 }
772);
773
774$csrf = $t->post_ok('/settings/oauth/register' => form => {
775 name => 'MyConfApp',
776 type => 'CONFIDENTIAL',
Akron6b75d122022-05-12 17:39:05 +0200777 desc => 'This is my plugin application',
Akronb6b156e2022-03-31 14:57:49 +0200778})
779 ->text_is('div.notify-error', 'Bad CSRF token')
780 ->tx->res->dom->at('input[name="csrf_token"]')
781 ->attr('value')
782 ;
783
784$t->post_ok('/settings/oauth/register' => form => {
785 name => 'MyConfApp',
786 type => 'CONFIDENTIAL',
787 desc => 'This is my confidential application',
788 csrf_token => $csrf,
789 redirect_uri => 'http://localhost/redirect-target'
790})
791 ->text_is('div.notify-error', undef)
792 ->text_is('li.client span.client-name', 'MyConfApp')
793 ->text_is('li.client p.client-desc', 'This is my confidential application')
794 ->text_is('li.client .client-redirect-uri tt', 'http://localhost/redirect-target')
795 ->text_is('li.client .client-type tt', 'CONFIDENTIAL')
796 ->element_exists_not('.client-issue-token')
797 ;
798
799$t->post_ok('/settings/oauth/register' => form => {
800 name => 'MyConfApp2',
801 type => 'CONFIDENTIAL',
802 desc => 'This is my second confidential application',
803 csrf_token => $csrf,
804 redirect_uri => 'http://localhost/FAIL'
805})
806 ->status_is(302)
807 ->header_is('location','/settings/oauth/')
808 ;
809
810$t->get_ok('/settings/oauth/')
811 ->text_is('div.notify-error', 'invalid_request: http://localhost/FAIL is invalid.')
812 ;
813
Akrona8efaa92022-04-09 14:45:43 +0200814# OAuth client authorization flow
815$t->get_ok(Mojo::URL->new('/settings/oauth/authorize'))
816 ->status_is(302)
Akron5ea0f5d2023-01-20 11:51:43 +0100817 ->header_is('location','/settings/oauth')
818 ;
819
820$t->get_ok('/settings/oauth/')
Akron2c142ab2023-01-30 13:21:57 +0100821 ->text_is('div.notify-error', 'Client ID required')
822 ;
823
824$t->get_ok(Mojo::URL->new('/settings/oauth/authorize?client_id=xyz'))
825 ->status_is(302)
826 ->header_is('location','/settings/oauth')
827 ;
828
829$t->get_ok('/settings/oauth/')
830 ->text_is('div.notify-error', 'Scope required')
Akrona8efaa92022-04-09 14:45:43 +0200831 ;
832
Akrondb1f4672023-01-24 12:05:07 +0100833# OAuth client authorization flow
834$t->get_ok(Mojo::URL->new('/settings/oauth/authorize?client_id=abc'))
835 ->status_is(302)
836 ->header_is('location','/settings/oauth')
837 ;
838
839$t->get_ok('/settings/oauth/')
Akron2c142ab2023-01-30 13:21:57 +0100840 ->text_is('div.notify-error', 'Scope required')
841 ;
842
843# OAuth client authorization flow
844$t->get_ok(Mojo::URL->new('/settings/oauth/authorize?client_id=abc&scope=match'))
845 ->status_is(302)
846 ->header_is('location','/settings/oauth')
847 ;
848
849$t->get_ok('/settings/oauth/')
Akrondb1f4672023-01-24 12:05:07 +0100850 ->text_is('div.notify-error', 'Unknown client with abc.')
851 ;
852
Akrona8efaa92022-04-09 14:45:43 +0200853# Logout
854$t->get_ok('/x/expired-with-wrong-refresh');
855
856$t->get_ok('/user/logout')
857 ->status_is(302)
858 ->session_hasnt('/auth')
859 ->session_hasnt('/auth_r')
860 ->session_hasnt('/user')
861 ->header_is('Location' => '/');
862
Akron001dcd22023-02-07 08:38:11 +0100863$t->get_ok('/')
Akrona8efaa92022-04-09 14:45:43 +0200864 ->status_is(200)
865 ->element_exists_not('div.notify-error')
866 ->element_exists('div.notify-success')
867 ->text_is('div.notify-success', 'Logout successful')
Akron9fa7cc52022-05-12 11:17:20 +0200868 ->element_exists("input[name=handle_or_email]")
Akron001dcd22023-02-07 08:38:11 +0100869 ;
870
871# OAuth client authorization flow - but user not logged in
872$t->get_ok(Mojo::URL->new('/settings/oauth/authorize'))
873 ->status_is(302)
874 ->header_is('location','/')
875 ;
876
877$csrf = $t->get_ok('/')
878 ->status_is(200)
879 ->element_exists('div.notify-error')
880 ->element_exists_not('div.notify-success')
881 ->text_is('div.notify-error', 'Client ID required')
882 ->element_exists("input[name=handle_or_email]")
Akrona8efaa92022-04-09 14:45:43 +0200883 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
884 ;
885
Akron408bc7c2022-04-28 15:46:43 +0200886$fake_backend_app->add_client({
887 "client_id" => 'xyz',
888 "client_name" => 'New added client',
889 "client_description" => 'This is a new client',
890 "client_url" => 'http://example.com',
891 "client_type" => 'CONFIDENTIAL'
892# "client_redirect_uri" => $redirect_uri
893});
894
Akron0cbcc072024-10-08 14:04:42 +0200895$fake_backend_app->add_client({
896 "client_id" => 'xyz-public',
897 "client_name" => 'New added public client',
898 "client_description" => 'This is a new public client',
899 "client_url" => 'http://example.com',
900 "client_type" => 'PUBLIC'
901# "client_redirect_uri" => $redirect_uri
902});
903
Helge278fbca2022-11-29 18:49:15 +0100904
Akron9d826902023-01-25 10:20:52 +0100905$fake_backend_app->add_client({
906 "client_id" => 'xyz2',
907 "client_name" => 'New added client',
908 "client_description" => 'This is a new client',
909 "client_url" => 'http://example.com',
910 "client_type" => 'CONFIDENTIAL',
911 "client_redirect_uri" => 'http://redirect.url/'
912});
913
Akroneb39cf32023-04-03 14:40:48 +0200914$t->get_ok('/settings/oauth/xyz2')
915 ->status_is(200)
916 ->text_is('li.client span.client-name','New added client')
917 ->attr_is('li.client p.client-url a','href','http://example.com')
918 ->attr_is('li.client input[name=client_id]','value','xyz2')
919 ->element_exists('li.client p.client-type-confidential')
920 ->text_is('li.client p.client-redirect-uri tt','http://redirect.url/')
921 ;
922
Akron9d826902023-01-25 10:20:52 +0100923$fwd = $t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
924 client_id => 'xyz2',
925 scope => 'search match',
926 redirect_uri => 'http://test.com/',
927}))
928 ->status_is(200)
929 ->text_is('div.notify-warn', 'redirect_uri host differs from registered host')
930 ->element_exists_not('div.notify-error')
931 ->element_exists_not('div.notify-success')
932 ->element_exists("input[name=handle_or_email]")
933 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
934 ;
935
936$fwd = $t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
937 client_id => 'xyz2',
938 scope => 'search match',
939 redirect_uri => 'http://redirect.url:9000/',
940}))
941 ->status_is(200)
942 ->text_is('div.notify-warn', 'redirect_uri port differs from registered port')
943 ->element_exists_not('div.notify-error')
944 ->element_exists_not('div.notify-success')
945 ->element_exists("input[name=handle_or_email]")
946 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
947 ;
948
Helge278fbca2022-11-29 18:49:15 +0100949
950$fake_backend_app->add_plugin({
951"source" => {"key1" => 'wert1', "key2" => 'wert2'},
Helge278fbca2022-11-29 18:49:15 +0100952"client_id" => '52abc',
Helgedb720ea2023-03-20 09:39:36 +0100953"permitted" => 'true',
Helge278fbca2022-11-29 18:49:15 +0100954"client_name" => 'Plugin 1',
955"client_type" => 'CONFIDENTIAL',
Helgedb720ea2023-03-20 09:39:36 +0100956"client_description" => 'Description Plugin 1',
957"client_url" => 'http://example.client.de',
958"registration_date" => '2022-05-31T14:30:09+02:00[Europe/Berlin]',
Helge216a4822024-06-17 12:02:34 +0200959"registered_by" => 'testuser',
960"refresh_token_expiry" => '7776000',
Helge278fbca2022-11-29 18:49:15 +0100961});
962
963
Akrona8efaa92022-04-09 14:45:43 +0200964$fwd = $t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
965 client_id => 'xyz',
966 state => 'abcde',
967 scope => 'search match',
968 redirect_uri => 'http://test.com/',
969}))
970 ->status_is(200)
971 ->attr_is('input[name=client_id]','value','xyz')
972 ->attr_is('input[name=state]','value','abcde')
Akrona8efaa92022-04-09 14:45:43 +0200973 ->attr_like('input[name=fwd]','value',qr!test\.com!)
Akron408bc7c2022-04-28 15:46:43 +0200974 ->text_is('span.client-name','New added client')
Akrona8efaa92022-04-09 14:45:43 +0200975 ->text_is('div.intro p:nth-child(2)', 'Please log in!')
976 ->tx->res->dom->at('input[name=fwd]')->attr('value')
977 ;
978
979$fwd = $t->post_ok(Mojo::URL->new('/user/login')->query({
980 csrf_token => $csrf,
981 client_id => 'xyz',
982 state => 'abcde',
983 scope => 'search match',
984 redirect_uri => 'http://test.com/',
Akron9fa7cc52022-05-12 11:17:20 +0200985 handle_or_email => 'test',
Akrona8efaa92022-04-09 14:45:43 +0200986 pwd => 'pass',
987 fwd => $fwd
988}))
989 ->status_is(302)
990 ->header_like('location', qr!/settings/oauth/authorize!)
991 ->tx->res->headers->header('location')
992 ;
993
994$t->get_ok($fwd)
995 ->status_is(200)
996 ->attr_is('input[name=client_id]','value','xyz')
997 ->attr_is('input[name=state]','value','abcde')
Akron9d826902023-01-25 10:20:52 +0100998 ->attr_like('input[name=redirect_uri]','value', qr!^http://test\.com\/\?crto=.{3,}!)
Akrona8efaa92022-04-09 14:45:43 +0200999 ->text_is('ul#scopes li:nth-child(1)','search')
1000 ->text_is('ul#scopes li:nth-child(2)','match')
Akron408bc7c2022-04-28 15:46:43 +02001001 ->text_is('span.client-name','New added client')
Akrona8efaa92022-04-09 14:45:43 +02001002 ->attr_is('a.form-button','href','http://test.com/')
1003 ->attr_is('a.embedded-link', 'href', '/doc/korap/kalamar')
Akron9d826902023-01-25 10:20:52 +01001004 ->element_exists_not('div.notify-error')
1005 ->element_exists_not('div.notify-warn')
1006 ->element_exists_not('blockquote.warning')
Akron0cbcc072024-10-08 14:04:42 +02001007 ->text_is('h2 + p', ' wants to have access')
Akrona8efaa92022-04-09 14:45:43 +02001008 ;
1009
Akron0cbcc072024-10-08 14:04:42 +02001010$fwd = $t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
1011 client_id => 'xyz-public',
1012 state => 'abcde',
1013 scope => 'search match',
1014 redirect_uri => 'http://test.com/',
1015}))
1016 ->status_is(200)
1017 ->attr_is('input[name=client_id]','value','xyz-public')
1018 ->attr_is('input[name=state]','value','abcde')
1019 ->attr_like('input[name=redirect_uri]','value', qr!^http://test\.com\/\?crto=.{3,}!)
1020 ->text_is('ul#scopes li:nth-child(1)','search')
1021 ->text_is('ul#scopes li:nth-child(2)','match')
1022 ->text_is('span.client-name','New added public client')
1023 ->attr_is('a.form-button','href','http://test.com/')
1024 ->attr_is('a.embedded-link', 'href', '/doc/korap/kalamar')
1025 ->element_exists_not('div.notify-error')
1026 ->element_exists_not('div.notify-warn')
1027 ->text_is('blockquote.warning','Warning - this is a public client!')
1028 ->text_is('h2 + p', ' wants to have access')
1029 ;
1030
1031
Helge278fbca2022-11-29 18:49:15 +01001032$t->get_ok('/settings/marketplace')
1033 ->status_is(200)
1034 ->text_is('html head title' => 'Marketplace')
1035 ->element_exists('ul.plugin-list')
1036 ->element_exists('ul.plugin-list > li')
Helge278fbca2022-11-29 18:49:15 +01001037 ->text_is('span.client-name','Plugin 1')
1038 ->text_is('p.plugin-desc','Description Plugin 1')
Helge216a4822024-06-17 12:02:34 +02001039 ->text_is('p.registration_date', 'Date of registration: 2022-05-31T14:30:09+02:00[Europe/Berlin]')
1040 ->text_is('p.registered_by', 'Registered by: testuser')
Helge278fbca2022-11-29 18:49:15 +01001041 ;
1042
Helgedb720ea2023-03-20 09:39:36 +01001043
1044
Helge278fbca2022-11-29 18:49:15 +01001045$fake_backend_app->add_plugin({
1046"source" => {"one" => '1', "two" => '2'},
1047"permitted" => 'false',
1048"client_id" => '53abc',
1049"client_name" => 'Plugin 2',
1050"client_type" => 'CONFIDENTIAL',
1051"client_description" =>'Description Plugin 2'
1052});
1053
Helge278fbca2022-11-29 18:49:15 +01001054$t->get_ok('/settings/marketplace')
1055 ->status_is(200)
1056 ->element_exists('ul.plugin-list')
1057 ->element_exists('ul.plugin-list > li')
1058 ->text_is('span.client-name','Plugin 1')
1059 ->text_is('p.plugin-desc','Description Plugin 1')
1060 ->element_exists('ul.plugin-list > li + li')
Helgedb720ea2023-03-20 09:39:36 +01001061 ->text_is('ul.plugin-list > li + li >span.client-name','Plugin 2')
1062 ->text_is('ul.plugin-list > li + li >p.plugin-desc','Description Plugin 2')
Helge278fbca2022-11-29 18:49:15 +01001063 ;
1064
Helged36478d2023-06-08 17:43:01 +02001065$t->post_ok('/settings/marketplace/install', form => {'client-id' => '52abc'})
Helgedb720ea2023-03-20 09:39:36 +01001066 ->status_is(302)
1067 ->header_is(location => '/settings/marketplace')
1068 ;
Helgedb720ea2023-03-20 09:39:36 +01001069$t->ua->max_redirects(1);
1070
Helged36478d2023-06-08 17:43:01 +02001071$t->post_ok('/settings/marketplace/install', form => {'client-id' => '52abc'})
Helgedb720ea2023-03-20 09:39:36 +01001072 ->status_is(200)
1073 ->element_exists('ul.plugin-list')
1074 ->element_exists('ul.plugin-list > li')
1075 ->text_is('ul.plugin-list > li > span.client-name','Plugin 2')
1076 ->text_is('ul.plugin-list > li > p.plugin-desc','Description Plugin 2')
1077 ->element_exists_not('ul.plugin-list > li + li')
1078 ->element_exists('ul.plugin_in-list')
1079 ->element_exists('ul.plugin_in-list > li')
1080 ->text_is('ul.plugin_in-list > li > span.client-name','Plugin 1')
Helge216a4822024-06-17 12:02:34 +02001081 ->text_is('ul.plugin_in-list > li > p.inst_date','Installation date: 2022-12-13T16:33:27.621+01:00[Europe/Berlin]')
Helgedb720ea2023-03-20 09:39:36 +01001082 ;
1083
1084$t->ua->max_redirects(0);
1085
Helged36478d2023-06-08 17:43:01 +02001086 $t->post_ok('/settings/marketplace/install', form => {'client-id' => 'unsinn31'})
Helgedb720ea2023-03-20 09:39:36 +01001087 ->status_is(302)
1088 ->header_is(location => '/settings/marketplace')
1089 ;
1090
1091$t->ua->max_redirects(1);
1092
Helged36478d2023-06-08 17:43:01 +02001093$t->post_ok('/settings/marketplace/install', form => {'client-id' => 'unsinn31'})
Helgedb720ea2023-03-20 09:39:36 +01001094 ->status_is(200)
1095 ->text_is('div.notify-error', 'Plugin could not be installed')
1096 ;
1097
Helged36478d2023-06-08 17:43:01 +02001098$t->post_ok('/settings/marketplace/uninstall', form => {'client-id' => '52abc'})
1099 ->status_is(200)
1100 ->element_exists('ul.plugin-list')
1101 ->element_exists('ul.plugin-list > li')
1102 ->text_is('span.client-name','Plugin 1')
1103 ->text_is('p.plugin-desc','Description Plugin 1')
1104 ->element_exists('ul.plugin-list > li + li')
1105 ->text_is('ul.plugin-list > li + li >span.client-name','Plugin 2')
1106 ->text_is('ul.plugin-list > li + li >p.plugin-desc','Description Plugin 2')
1107 ->element_exists_not('ul.plugin_in-list')
1108 ;
1109
1110$t->post_ok('/settings/marketplace/uninstall', form => {'client-id' => 'quatsch12'})
1111 ->status_is(200)
1112 ->text_is('div.notify-error', 'Plugin could not be uninstalled')
1113 ;
1114
Helgedb720ea2023-03-20 09:39:36 +01001115$t->ua->max_redirects(0);
Helge278fbca2022-11-29 18:49:15 +01001116
Akrona8efaa92022-04-09 14:45:43 +02001117$t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
1118 client_id => 'xyz',
1119 state => 'abcde',
1120 scope => 'search match',
1121 redirect_uri => 'http://test.com/'
1122}))
1123 ->status_is(200)
1124 ->attr_is('input[name=client_id]','value','xyz')
1125 ->attr_is('input[name=state]','value','abcde')
Akrona8efaa92022-04-09 14:45:43 +02001126 ->text_is('ul#scopes li:nth-child(1)','search')
1127 ->text_is('ul#scopes li:nth-child(2)','match')
Akron408bc7c2022-04-28 15:46:43 +02001128 ->text_is('span.client-name','New added client')
Akrona8efaa92022-04-09 14:45:43 +02001129 ->attr_is('a.form-button','href','http://test.com/')
1130 ->attr_is('a.embedded-link', 'href', '/doc/korap/kalamar')
1131 ;
1132
1133$t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
1134 client_id => 'xyz',
1135 state => 'abcde',
1136 scope => 'search match',
1137 redirect_uri => 'http://test.com/'
1138}))
1139 ->status_is(302)
Akron9d826902023-01-25 10:20:52 +01001140 ->header_is('location', '/settings/oauth?error_description=Bad+CSRF+token')
Akrona8efaa92022-04-09 14:45:43 +02001141 ;
1142
Akrona8f87cc2023-02-23 12:21:30 +01001143
1144my $local_port = $t->get_ok('/')->tx->local_port;
1145my $remote_port = $t->get_ok('/')->tx->remote_port;
1146
1147like($local_port, qr!^\d+$!);
1148like($remote_port, qr!^\d+$!);
1149
1150my $port = $remote_port;
1151
1152my $redirect_url_fakeapi = $t->app->close_redirect_to(Mojo::URL->new('http://localhost:' . $port)->path($fake_backend_app->url_for('return_uri'))->to_abs->to_string);
1153
Akrona8efaa92022-04-09 14:45:43 +02001154$fwd = $t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
1155 client_id => 'xyz',
1156 state => 'abcde',
1157 scope => 'search match',
Akrona8f87cc2023-02-23 12:21:30 +01001158 redirect_uri_server => 'http://localhost:'.$port,
1159 redirect_uri => "$redirect_url_fakeapi",
Akrona8efaa92022-04-09 14:45:43 +02001160 csrf_token => $csrf,
1161}))
1162 ->status_is(302)
Akrona8f87cc2023-02-23 12:21:30 +01001163 ->header_like('location', qr!^http://localhost:\d+/realapi/fakeclient/return\?code=.+$!)
Akrona8efaa92022-04-09 14:45:43 +02001164 ->tx->res->headers->header('location')
1165 ;
1166
Akronf47813c2023-05-08 16:24:03 +02001167unless ($^O eq 'MSWin32') {
1168 $t->get_ok($fwd)
1169 ->status_is(200)
1170 ->content_like(qr'welcome back! \[(.+?)\]')
1171 ;
1172};
Akrona8efaa92022-04-09 14:45:43 +02001173
Akrona8f87cc2023-02-23 12:21:30 +01001174my $fake_port = $port;
1175
1176while ($fake_port == $remote_port || $fake_port == $local_port) {
1177 $fake_port++;
1178};
1179
1180$redirect_url_fakeapi = $t->app->close_redirect_to(Mojo::URL->new('http://localhost:' . $fake_port)->path($fake_backend_app->url_for('return_uri'))->to_abs->to_string);
1181
1182$fwd = $t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
1183 client_id => 'xyz',
1184 state => 'abcde',
1185 scope => 'search match',
1186 redirect_uri_server => 'http://localhost:'.$port,
1187 redirect_uri => "$redirect_url_fakeapi",
1188 csrf_token => $csrf,
1189}))
1190 ->status_is(302)
1191 ->header_unlike('location', qr!^http://localhost:\d+/realapi/fakeclient/return\?error_description=Connection\+refused$!)
1192 ->header_like('location', qr!^http://localhost:\d+/realapi/fakeclient/return\?code=.+?$!)
1193 ->tx->res->headers->header('location')
1194 ;
1195
Akrona8efaa92022-04-09 14:45:43 +02001196$t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
1197 client_id => 'xyz',
Akron9ccf69a2023-01-31 14:21:37 +01001198 state => 'abcde',
1199 scope => 'search match',
1200 redirect_uri_server => 'http://example.com/',
1201 redirect_uri => $t->app->close_redirect_to('http://wrong'),
1202 csrf_token => $csrf,
1203}))
1204 ->status_is(302)
1205 ->header_is('location', '/settings/oauth')
1206 ->tx->res->headers->header('location')
1207 ;
1208
1209$t->get_ok('/settings/oauth')
1210 ->text_is('div.notify-error', 'Invalid redirect URI')
1211 ;
1212
1213$t->post_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
1214 client_id => 'xyz',
Akrona8efaa92022-04-09 14:45:43 +02001215 state => 'fail',
1216 scope => 'search match',
Akron9d826902023-01-25 10:20:52 +01001217# redirect_uri_server => 'http://example.com/',
Akrona8efaa92022-04-09 14:45:43 +02001218 redirect_uri => $fake_backend_app->url_for('return_uri')->to_abs,
1219 csrf_token => $csrf,
1220}))
1221 ->status_is(302)
Akron9d826902023-01-25 10:20:52 +01001222 ->header_is('location', '/realapi/fakeclient/return?error_description=FAIL')
Akrona8efaa92022-04-09 14:45:43 +02001223 ;
1224
Akron9f2ad342022-05-04 16:16:40 +02001225my $json_post = {
1226 name => 'Funny',
1227 type => 'PUBLIC',
Akron6b75d122022-05-12 17:39:05 +02001228 desc => 'This is my plugin application 2',
Helge9f9d4852024-12-09 16:06:34 +01001229 url => 'https://xyz/123',
Akron9f2ad342022-05-04 16:16:40 +02001230 csrf_token => $csrf,
1231 src => 'hMMM'
1232};
1233
Helge9f9d4852024-12-09 16:06:34 +01001234
Akron9f2ad342022-05-04 16:16:40 +02001235$t->post_ok('/settings/oauth/register' => form => $json_post)
1236 ->status_is(200)
1237 ->element_exists('div.notify-error')
Akron99968a92022-06-03 12:32:07 +02001238 ->text_is('div.notify-error', 'Plugin declarations need to be json files')
1239 ;
1240
1241$json_post->{src} = {
1242 content => 'jjjjjj',
1243 filename => 'fun.txt'
1244};
1245
1246$t->post_ok('/settings/oauth/register' => form => $json_post)
1247 ->status_is(200)
1248 ->element_exists('div.notify-error')
Akron9f2ad342022-05-04 16:16:40 +02001249 ->text_is('div.notify-error', 'Plugins need to be confidential')
1250 ;
1251
1252$json_post->{type} = 'CONFIDENTIAL';
1253
Akron99968a92022-06-03 12:32:07 +02001254# This somehow gets removed in the last form send ...
Akron9f2ad342022-05-04 16:16:40 +02001255$json_post->{src} = {
1256 content => 'jjjjjj',
1257 filename => 'fun.txt'
1258};
1259
1260$t->post_ok('/settings/oauth/register' => form => $json_post)
1261 ->status_is(200)
1262 ->element_exists('div.notify-error')
1263 ->text_is('div.notify-error', 'Plugin declarations need to be json files')
1264 ;
1265
1266$json_post->{src} = {
1267 content => '{"name":"example"}',
1268 filename => 'fun.txt'
1269};
1270
1271$t->post_ok('/settings/oauth/register' => form => $json_post)
1272 ->status_is(200)
1273 ->element_exists_not('div.notify-error')
1274 ->element_exists('div.notify-success')
1275 ->text_is('div.notify-success', 'Registration successful')
1276 ;
1277
Akron6b75d122022-05-12 17:39:05 +02001278$t->get_ok('/settings/oauth/jh0gfjhjbfdsgzjghj==')
1279 ->status_is(200)
1280 ->text_is('div.notify-error', undef)
1281 ->text_is('li.client #client_source', '{"name":"example"}')
1282 ->text_is('li.client span.client-name', 'Funny')
1283 ->text_is('li.client p.client-desc', 'This is my plugin application 2')
1284 ->element_exists_not('li.client .client-redirect-uri tt')
1285 ->text_is('li.client .client-type tt', 'CONFIDENTIAL')
1286 ;
Akron9f2ad342022-05-04 16:16:40 +02001287
Akronb6b156e2022-03-31 14:57:49 +02001288
Akron66ef3b52022-11-22 14:25:15 +01001289# Retest client with super_client_file
1290my $client_file = tempfile;
1291
Akron889bc202024-03-15 17:16:55 +01001292$client_file->spew(
Akron66ef3b52022-11-22 14:25:15 +01001293 '{"client_id":"2","client_secret":"k414m4r-s3cr3t"}'
1294);
1295
1296$t = Test::Mojo::WithRoles->new('Kalamar' => {
1297 Kalamar => {
1298 plugins => ['Auth']
1299 },
1300 'Kalamar-Auth' => {
1301 client_file => $client_file,
1302 oauth2 => 1
1303 }
1304});
1305
1306$t->app->plugin(
1307 Mount => {
1308 $mount_point =>
1309 $fixtures_path->child('mock.pl')
1310 }
1311);
1312
1313$csrf = $t->get_ok('/')
1314 ->status_is(200)
1315 ->element_exists_not('div.button.top a')
1316 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
1317 ;
1318
1319$t->post_ok('/user/login' => form => {
1320 handle_or_email => 'test',
1321 pwd => 'pass',
1322 csrf_token => $csrf
1323})
1324 ->status_is(302)
1325 ->header_is('Location' => '/')
1326 ->content_is('');
1327
1328$t->get_ok('/')
1329 ->status_is(200)
1330 ->element_exists_not('div.notify-error')
1331 ->element_exists('div.notify-success')
1332 ->text_is('div.notify-success', 'Login successful')
1333 ->element_exists_not('aside.off')
1334 ->element_exists_not('aside.active')
1335 ->element_exists('aside.settings')
1336 ;
1337
Akron53a171e2022-12-05 18:22:58 +01001338$main::ENV{KALAMAR_CLIENT_FILE} = $client_file;
1339
1340$t = Test::Mojo::WithRoles->new('Kalamar' => {
1341 Kalamar => {
1342 plugins => ['Auth']
1343 },
1344 'Kalamar-Auth' => {
1345 oauth2 => 1,
1346# client_file => $client_file,
1347 }
1348});
1349
1350$t->app->plugin(
1351 Mount => {
1352 $mount_point =>
1353 $fixtures_path->child('mock.pl')
1354 }
1355);
1356
1357$csrf = $t->get_ok('/')
1358 ->status_is(200)
1359 ->element_exists_not('div.button.top a')
1360 ->tx->res->dom->at('input[name=csrf_token]')->attr('value')
1361 ;
1362
1363$t->post_ok('/user/login' => form => {
1364 handle_or_email => 'test',
1365 pwd => 'pass',
1366 csrf_token => $csrf
1367})
1368 ->status_is(302)
1369 ->header_is('Location' => '/')
1370 ->content_is('');
1371
1372$t->get_ok('/')
1373 ->status_is(200)
1374 ->element_exists_not('div.notify-error')
1375 ->element_exists('div.notify-success')
1376 ->text_is('div.notify-success', 'Login successful')
1377 ->element_exists_not('aside.off')
1378 ->element_exists_not('aside.active')
1379 ->element_exists('aside.settings')
1380 ;
1381
Akron83224302026-01-21 12:05:51 +01001382$log_output = '';
Akron66ef3b52022-11-22 14:25:15 +01001383
Akron83224302026-01-21 12:05:51 +01001384# Test non-existing client file (app should initialize without crashing)
1385$t = Test::Mojo->new('Kalamar');
1386$t->app->log->handle($log_fh);
1387$t->app->log->level('error');
1388$t->app->plugin('Mount' => {
1389 $mount_point => $fixtures_path->child('mock.pl')
1390});
1391
1392$t->app->plugin('Auth' => {
1393 client_file => '/nonexistent/client.json',
1394 oauth2 => 1
1395 }
1396);
1397ok($t->app, 'App initializes with non-existing client file');
1398like($log_output, qr'provided client file does not exist', 'Check log is fine');
1399
1400$log_output = '';
1401
1402# Test malformed JSON client file (app should initialize without crashing)
1403my $bad_client_file = tempfile();
1404$bad_client_file->spew('{invalid json}');
1405$t = Test::Mojo->new('Kalamar');
1406$t->app->log->handle($log_fh);
1407$t->app->log->level('error');
1408$t->app->plugin('Mount' => {
1409 $mount_point => $fixtures_path->child('mock.pl')
1410});
1411
1412$t->app->plugin('Auth' => {
1413 client_file => $bad_client_file->to_string,
1414 oauth2 => 1
1415 }
1416);
1417ok($t->app, 'App initializes with malformed JSON client file');
1418like($log_output, qr'provided client file syntax invalid', 'Check log is fine');
Akron33f5c672019-06-24 19:40:47 +02001419done_testing;
1420__END__
Akrona8efaa92022-04-09 14:45:43 +02001421
1422