blob: 7650e022038bed5ac5f29c63f4132b681a1fd156 [file] [log] [blame]
Akron80027d12016-01-20 17:36:36 +01001package Kalamar::Plugin::KalamarUser;
2use Mojo::Base 'Mojolicious::Plugin';
3use Mojo::ByteStream 'b';
4
5has 'api';
Akrondadacf12016-01-22 19:24:59 +01006has 'ua';
Akron80027d12016-01-20 17:36:36 +01007
Akronc86bbc42017-03-29 13:19:06 +02008# TODO: Merge with meta-button
9
Akron80027d12016-01-20 17:36:36 +010010sub register {
11 my ($plugin, $mojo, $param) = @_;
12
13 # Load parameter from config file
14 if (my $config_param = $mojo->config('Kalamar')) {
15 $param = { %$param, %$config_param };
16 };
17
Akron2cb9a3d2016-02-09 23:59:46 +010018 # Load 'notifications' plugin
19 unless (exists $mojo->renderer->helpers->{notify}) {
20 $mojo->plugin(Notifications => {
21 HTML => 1
22 });
23 };
24
Akron80027d12016-01-20 17:36:36 +010025 # Set API!
26 $plugin->api($param->{api}) or return;
Akrondadacf12016-01-22 19:24:59 +010027 $plugin->ua(Mojo::UserAgent->new);
Akron80027d12016-01-20 17:36:36 +010028
29 # Get the user token necessary for authorization
30 $mojo->helper(
31 'user_auth' => sub {
32 my $c = shift;
33
34 # Get token from stash
35 my $token = $c->stash('auth');
36 return $token if $token;
37
38 # Set token to stash
39 $c->stash(auth => $c->session('auth'));
40 return $c->stash('auth');
41 }
42 );
43
44 # Login
45 $mojo->helper(
46 'user.login' => sub {
47 my $c = shift;
48 my ($user, $pwd) = @_;
49
Akrondadacf12016-01-22 19:24:59 +010050 return if (index($user, ':') >= 0);
Akron80027d12016-01-20 17:36:36 +010051
52 my $url = Mojo::URL->new($plugin->api)->path('auth/apiToken');
53 my $tx = $c->ua->get($url => {
Akronc86bbc42017-03-29 13:19:06 +020054 Authorization => 'Basic ' . b($user . ':' . $pwd)->b64_encode
Akron80027d12016-01-20 17:36:36 +010055 });
56
57 # Login successful
58 if (my $res = $tx->success) {
Akrone8235be2016-06-27 11:02:18 +020059
Akronc86bbc42017-03-29 13:19:06 +020060 my $jwt = $res->json;
Akron80027d12016-01-20 17:36:36 +010061
Akronc86bbc42017-03-29 13:19:06 +020062 my $auth = $jwt->{token_type} . ' ' . $jwt->{token};
Akron80027d12016-01-20 17:36:36 +010063
Akronc86bbc42017-03-29 13:19:06 +020064 $mojo->log->debug(qq!Login successful: "$user" with "$auth"!);
Akron80027d12016-01-20 17:36:36 +010065
Akronc86bbc42017-03-29 13:19:06 +020066 # Set session info
67 $c->session(user => $user);
68 $c->session(auth => $auth);
Akron80027d12016-01-20 17:36:36 +010069
Akronc86bbc42017-03-29 13:19:06 +020070 $c->stash(user => $user);
71 $c->stash(auth => $auth);
Akron80027d12016-01-20 17:36:36 +010072
Akronc86bbc42017-03-29 13:19:06 +020073 # Set cache
74 $c->chi('user')->set($auth => $user);
75 return 1;
Akron2cb9a3d2016-02-09 23:59:46 +010076 }
77
78 elsif (my $e = $tx->error) {
Akronc86bbc42017-03-29 13:19:06 +020079 $c->notify(
80 error =>
81 ($e->{code} ? $e->{code} . ': ' : '') .
82 $e->{message} . ' for Login (remote)'
83 );
Akron80027d12016-01-20 17:36:36 +010084 };
85
86 $mojo->log->debug(qq!Login fail: "$user"!);
87
88 return;
89 }
90 );
91
92 # Get details, settings etc. with authorization
93 $mojo->helper(
94 'user.get' => sub {
95 my $c = shift;
96 my $param = shift;
97
Akrone8235be2016-06-27 11:02:18 +020098 # 'info' is useless!
Akrondadacf12016-01-22 19:24:59 +010099 return unless $param =~ m/^details|settings$/;
Akron80027d12016-01-20 17:36:36 +0100100
101 # The user may be logged in
102 my $auth = ($c->stash('auth') || $c->session('auth')) or return;
103
104 # Get namespaced cache
105 my $chi = $c->chi('user');
106
107 # Get user and check, if the user is real
108 my $user = $chi->get($auth);
109
110 # Check if the user is really logged in
111 my $value = $chi->get($user . '_' . $param);
112
113 unless ($value) {
Akrondadacf12016-01-22 19:24:59 +0100114
Akronc86bbc42017-03-29 13:19:06 +0200115 my $tx = $plugin->build_authorized_tx($auth, 'GET', 'user/' . $param);
116 $tx = $plugin->ua->start($tx);
Akrone8235be2016-06-27 11:02:18 +0200117
Akronc86bbc42017-03-29 13:19:06 +0200118 unless ($value = $tx->success) {
119 return;
120 }
121 # else {
122 # warn $c->dumper($value->json);
123 # };
124 if ($value) {
125 $value = $value->json;
126 };
Akrondadacf12016-01-22 19:24:59 +0100127
Akronc86bbc42017-03-29 13:19:06 +0200128 $chi->set($user . '_' . $param => $value);
Akron80027d12016-01-20 17:36:36 +0100129 };
130
131 # Return value
132 return $value;
133 }
134 );
135
Akrone8235be2016-06-27 11:02:18 +0200136 $mojo->helper(
137 'user.set' => sub {
138 my $c = shift;
139 my $param = shift;
140
141 # 'info' is useless!
142 return unless $param =~ m/^details|settings$/;
143
144 my $json_obj = shift;
145
146 # The user may be logged in
147 my $auth = ($c->stash('auth') || $c->session('auth')) or return;
148
149 # Get namespaced cache
150 my $chi = $c->chi('user');
151
152 # Get user and check, if the user is real
153 my $user = $chi->get($auth);
154
155 # Build a JSON transaction object
156 my $tx = $plugin->build_authorized_tx(
Akronc86bbc42017-03-29 13:19:06 +0200157 $auth, 'POST', 'user/' . $param, json => $json_obj
Akrone8235be2016-06-27 11:02:18 +0200158 );
159
160 # Start
161 $tx = $plugin->ua->start($tx);
162
163 my $res = $tx->success or return;
164
165 # Kill all caches!!
166 $chi->remove($user . '_' . $param);
167
168 # Return value
169 return $res->json;
170 }
171 );
Akron80027d12016-01-20 17:36:36 +0100172
173 # Logout
174 $mojo->helper(
175 'user.logout' => sub {
176 my $c = shift;
177
178 # TODO: csrf-protection!
179 # TODO: REVOKE ON THE SERVER ONCE SUPPORTED!
180
181 # Clear cache
182 $c->chi('user')->remove($c->user_auth);
183
184 # Expire session
185 $c->session(expires => 1);
186 return $c->redirect_to('index');
187 }
188 );
189};
190
Akronc86bbc42017-03-29 13:19:06 +0200191
Akrondadacf12016-01-22 19:24:59 +0100192sub build_authorized_tx {
Akron80027d12016-01-20 17:36:36 +0100193 my $plugin = shift;
194
Akrondadacf12016-01-22 19:24:59 +0100195 my $ua = $plugin->ua;
196 my ($auth, $method, $path, @values) = @_;
197
198 my $header;
199 if (@values && ref $values[0] eq 'HASH') {
200 $header = shift @values;
201 }
202 else {
203 $header = {};
204 };
205
Akron80027d12016-01-20 17:36:36 +0100206 my $url = Mojo::URL->new($plugin->api)->path($path);
207
Akrondadacf12016-01-22 19:24:59 +0100208 $header->{Authorization} = $auth;
Akron80027d12016-01-20 17:36:36 +0100209
Akrondadacf12016-01-22 19:24:59 +0100210 return $ua->build_tx($method, $url => $header => @values);
Akron80027d12016-01-20 17:36:36 +0100211};
212
213
2141;
215
216
217__END__
Akrondadacf12016-01-22 19:24:59 +0100218
219# Failure
220entity {
221 "errors":[
222 [204,"authentication token is expired","eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0MSIsImlzcyI6Imh0dHA6IiwiZXhwIjoxNDUyOTY2NzAxOTYxfQ.W_rJjJ8i82Srw7MiSPRGeIBLE-rMPmSPK9BA7Dt_7Yc"]
223 ]
224}
225