diff options
Diffstat (limited to 'lib')
-rwxr-xr-x | lib/Travelynx.pm | 22 | ||||
-rw-r--r-- | lib/Travelynx/Command/database.pm | 19 | ||||
-rw-r--r-- | lib/Travelynx/Controller/Traewelling.pm | 90 | ||||
-rw-r--r-- | lib/Travelynx/Helper/Traewelling.pm | 78 | ||||
-rw-r--r-- | lib/Travelynx/Model/Traewelling.pm | 7 |
5 files changed, 103 insertions, 113 deletions
diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index f5f56b7..551c061 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -100,6 +100,23 @@ sub startup { }, } ); + + if ( my $oa = $self->config->{traewelling}{oauth} ) { + $self->plugin( + OAuth2 => { + providers => { + traewelling => { + key => $oa->{id}, + secret => $oa->{secret}, + authorize_url => +'https://traewelling.de/oauth/authorize?response_type=code', + token_url => 'https://traewelling.de/oauth/token', + } + } + } + ); + } + $self->sessions->default_expiration( 60 * 60 * 24 * 180 ); # Starting with v8.11, Mojolicious sends SameSite=Lax Cookies by default. @@ -2140,6 +2157,11 @@ sub startup { $r->post('/login')->to('account#do_login'); $r->post('/recover')->to('account#request_password_reset'); + if ( $self->config->{traewelling}{oauth} ) { + $r->get('/oauth/traewelling')->to('traewelling#oauth'); + $r->post('/oauth/traewelling')->to('traewelling#oauth'); + } + if ( not $self->config->{registration}{disabled} ) { $r->get('/register')->to('account#registration_form'); $r->post('/register')->to('account#register'); diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm index 10732ec..b45a02f 100644 --- a/lib/Travelynx/Command/database.pm +++ b/lib/Travelynx/Command/database.pm @@ -1815,6 +1815,25 @@ my @migrations = ( } ); }, + + # v45 -> v46 + # Switch to Traewelling OAuth2 authentication. + # E-Mail is no longer needed. + sub { + my ($db) = @_; + $db->query( + qq{ + drop view traewelling_str; + create view traewelling_str as select + user_id, push_sync, pull_sync, errored, token, data, + extract(epoch from latest_run) as latest_run_ts + from traewelling + ; + alter table traewelling drop column email; + update schema_version set version = 46; + } + ); + }, ); # TODO add 'hafas' column to in_transit (and maybe journeys? undo/redo needs something to work with...) diff --git a/lib/Travelynx/Controller/Traewelling.pm b/lib/Travelynx/Controller/Traewelling.pm index 4c6bc64..e14872d 100644 --- a/lib/Travelynx/Controller/Traewelling.pm +++ b/lib/Travelynx/Controller/Traewelling.pm @@ -6,11 +6,9 @@ package Travelynx::Controller::Traewelling; use Mojo::Base 'Mojolicious::Controller'; use Mojo::Promise; -sub settings { +sub oauth { my ($self) = @_; - my $uid = $self->current_user->{id}; - if ( $self->param('action') and $self->validation->csrf_protect->has_error('csrf_token') ) { @@ -22,38 +20,68 @@ sub settings { return; } - if ( $self->param('action') and $self->param('action') eq 'login' ) { - my $email = $self->param('email'); - my $password = $self->param('password'); - $self->render_later; - $self->traewelling_api->login_p( - uid => $uid, - email => $email, - password => $password - )->then( - sub { - my $traewelling = $self->traewelling->get( uid => $uid ); - $self->param( sync_source => 'none' ); - $self->render( - 'traewelling', - traewelling => $traewelling, - new_traewelling => 1, - ); + $self->render_later; + + my $oa = $self->config->{traewelling}{oauth}; + + return $self->oauth2->get_token_p( + traewelling => { scope => 'read-statuses write-statuses' } )->then( + sub { + my ($provider) = @_; + if ( not defined $provider ) { + + # OAuth2 plugin performed a redirect, no need to render + return; } - )->catch( - sub { - my ($err) = @_; - $self->render( - 'traewelling', - traewelling => {}, - new_traewelling => 1, - login_error => $err, - ); + if ( not $provider or not $provider->{access_token} ) { + $self->flash( new_traewelling => 1 ); + $self->flash( login_error => 'no token received' ); + $self->redirect_to('/account/traewelling'); + return; } - )->wait; + my $uid = $self->current_user->{id}; + my $token = $provider->{access_token}; + $self->traewelling->link( + uid => $self->current_user->{id}, + token => $provider->{access_token}, + expires_in => $provider->{expires_in}, + ); + return $self->traewelling_api->get_user_p( $uid, $token )->then( + sub { + $self->flash( new_traewelling => 1 ); + $self->redirect_to('/account/traewelling'); + } + ); + } + )->catch( + sub { + my ($err) = @_; + say "error $err"; + $self->flash( new_traewelling => 1 ); + $self->flash( login_error => $err ); + $self->redirect_to('/account/traewelling'); + return; + } + ); +} + +sub settings { + my ($self) = @_; + + my $uid = $self->current_user->{id}; + + if ( $self->param('action') + and $self->validation->csrf_protect->has_error('csrf_token') ) + { + $self->render( + 'bad_request', + csrf => 1, + status => 400 + ); return; } - elsif ( $self->param('action') and $self->param('action') eq 'logout' ) { + + if ( $self->param('action') and $self->param('action') eq 'logout' ) { $self->render_later; my $traewelling = $self->traewelling->get( uid => $uid ); $self->traewelling_api->logout_p( diff --git a/lib/Travelynx/Helper/Traewelling.pm b/lib/Travelynx/Helper/Traewelling.pm index 23170eb..18edc18 100644 --- a/lib/Travelynx/Helper/Traewelling.pm +++ b/lib/Travelynx/Helper/Traewelling.pm @@ -199,84 +199,6 @@ sub get_user_p { return $promise; } -sub login_p { - my ( $self, %opt ) = @_; - - my $uid = $opt{uid}; - my $email = $opt{email}; - my $password = $opt{password}; - - my $ua = $self->{user_agent}->request_timeout(20); - - my $request = { - login => $email, - password => $password, - }; - - my $promise = Mojo::Promise->new; - my $token; - - $ua->post_p( - "https://traewelling.de/api/v1/auth/login" => $self->{header}, - json => $request - )->then( - sub { - my ($tx) = @_; - if ( my $err = $tx->error ) { - my $err_msg - = "v1/auth/login: HTTP $err->{code} $err->{message}"; - $promise->reject($err_msg); - return; - } - else { - my $res = $tx->result->json->{data}; - $token = $res->{token}; - my $expiry_dt = $self->parse_datetime( $res->{expires_at} ); - - # Fall back to one year expiry - $expiry_dt //= DateTime->now( time_zone => 'Europe/Berlin' ) - ->add( years => 1 ); - $self->{model}->link( - uid => $uid, - email => $email, - token => $token, - expires => $expiry_dt - ); - return $self->get_user_p( $uid, $token ); - } - } - )->then( - sub { - $promise->resolve; - return; - } - )->catch( - sub { - my ($err) = @_; - if ($token) { - - # We have a token, but couldn't complete the login. For now, we - # solve this by logging out and invalidating the token. - $self->logout_p( - uid => $uid, - token => $token - )->finally( - sub { - $promise->reject("v1/auth/login: $err"); - return; - } - ); - } - else { - $promise->reject("v1/auth/login: $err"); - } - return; - } - )->wait; - - return $promise; -} - sub logout_p { my ( $self, %opt ) = @_; diff --git a/lib/Travelynx/Model/Traewelling.pm b/lib/Travelynx/Model/Traewelling.pm index 1939374..72ee92d 100644 --- a/lib/Travelynx/Model/Traewelling.pm +++ b/lib/Travelynx/Model/Traewelling.pm @@ -38,16 +38,15 @@ sub now { sub link { my ( $self, %opt ) = @_; - my $log = [ [ $self->now->epoch, "Erfolgreich angemeldet" ] ]; + my $log = [ [ $self->now->epoch, "Erfolgreich mittels OAuth2 verbunden" ] ]; my $data = { log => $log, - expires => $opt{expires}->epoch, + expires => $self->now->epoch + $opt{expires_in}, }; my $user_entry = { user_id => $opt{uid}, - email => $opt{email}, push_sync => 0, pull_sync => 0, token => $opt{token}, @@ -59,7 +58,7 @@ sub link { $user_entry, { on_conflict => \ -'(user_id) do update set email = EXCLUDED.email, token = EXCLUDED.token, push_sync = false, pull_sync = false, data = null, errored = false, latest_run = null' +'(user_id) do update set token = EXCLUDED.token, push_sync = false, pull_sync = false, data = null, errored = false, latest_run = null' } ); |