Commit fd608391 authored by Birte Kristina Friesel's avatar Birte Kristina Friesel
Browse files

switch from HTTP Auth to Cookie Auth

parent ba6b517e
Loading
Loading
Loading
Loading
+191 −255
Original line number Diff line number Diff line
@@ -44,13 +44,10 @@ app->plugin(
	authentication => {
		autoload_user => 1,
		session_key   => 'foodor',
		fail_render   => { template => 'login' },
		load_user     => sub {
			my ( $self, $uid ) = @_;
			my $data = $self->get_user_data($uid);
			if ($data) {
				return { name => $data->{name} };
			}
			return undef;
			return $self->get_user_data($uid);
		},
		validate_user => sub {
			my ( $self, $username, $password, $extradata ) = @_;
@@ -68,6 +65,7 @@ app->plugin(
		},
	}
);
app->sessions->default_expiration( 60 * 60 * 24 * 180 );

app->defaults( layout => 'default' );

@@ -427,7 +425,7 @@ helper 'checkin' => sub {
			}

			my $success = $self->app->checkin_query->execute(
				$self->get_user_id,
				$self->current_user->{id},
				$self->get_station_id(
					ds100 => $status->{station_ds100},
					name  => $status->{station_name}
@@ -457,7 +455,7 @@ helper 'checkin' => sub {
helper 'undo' => sub {
	my ($self) = @_;

	my $uid = $self->get_user_id;
	my $uid = $self->current_user->{id};
	$self->app->get_last_actions_query->execute($uid);
	my $rows = $self->app->get_last_actions_query->fetchall_arrayref;

@@ -469,8 +467,8 @@ helper 'undo' => sub {
		return 'Repeated undo is not supported';
	}

	my $success
	  = $self->app->undo_query->execute( $self->get_user_id,
	my $success = $self->app->undo_query->execute(
		$self->current_user->{id},
		DateTime->now( time_zone => 'Europe/Berlin' )->epoch,
	);

@@ -501,7 +499,7 @@ helper 'checkout' => sub {
	if ( not defined $train ) {
		if ($force) {
			my $success = $self->app->checkout_query->execute(
				$self->get_user_id,
				$self->current_user->{id},
				$self->get_station_id(
					ds100 => $status->{station_ds100},
					name  => $status->{station_name}
@@ -523,7 +521,7 @@ helper 'checkout' => sub {
	}
	else {
		my $success = $self->app->checkout_query->execute(
			$self->get_user_id,
			$self->current_user->{id},
			$self->get_station_id(
				ds100 => $status->{station_ds100},
				name  => $status->{station_name}
@@ -580,7 +578,7 @@ helper 'get_user_token' => sub {
helper 'get_user_data' => sub {
	my ( $self, $uid ) = @_;

	$uid //= $self->get_user_id;
	$uid //= $self->current_user->{id};
	my $query = $self->app->get_user_query;
	$query->execute($uid);
	my $rows = $query->fetchall_arrayref;
@@ -603,7 +601,7 @@ helper 'get_user_data' => sub {
			deletion_requested => $row[7]
		};
	}
	return;
	return undef;
};

helper 'get_user_password' => sub {
@@ -623,80 +621,9 @@ helper 'get_user_password' => sub {
	return;
};

helper 'get_user_name' => sub {
	my ($self) = @_;

	my $user = $self->req->headers->header('X-Remote-User') // 'dev';

	return $user;
};

helper 'get_user_id' => sub {
helper 'add_user' => sub {
	my ( $self, $user_name, $email, $token, $password ) = @_;

	$user_name //= $self->get_user_name;

	if ( not -e $dbname ) {
		$self->app->dbh->begin_work;
		$self->app->dbh->do(
			qq{
			create table schema_version (
				version integer primary key
			);
		}
		);
		$self->app->dbh->do(
			qq{
			create table users (
				id integer primary key,
				name char(64) not null unique,
				status int not null,
				public_level bool not null,
				email char(256),
				token char(80),
				password text,
				registered_at datetime not null,
				last_login datetime not null,
				deletion_requested datetime
			)
		}
		);
		$self->app->dbh->do(
			qq{
			create table stations (
				id integer primary key,
				ds100 char(16) not null unique,
				name char(64) not null unique
			)
		}
		);
		$self->app->dbh->do(
			qq{
			create table user_actions (
				user_id int not null,
				action_id int not null,
				station_id int,
				action_time int not null,
				train_type char(16),
				train_line char(16),
				train_no char(16),
				train_id char(128),
				sched_time int,
				real_time int,
				route text,
				messages text,
				primary key (user_id, action_time)
			)
		}
		);
		$self->app->dbh->do(
			qq{
			insert into schema_version (version) values (1);
		}
		);
		$self->app->dbh->commit;
	}

	$self->app->get_userid_query->execute($user_name);
	my $rows = $self->app->get_userid_query->fetchall_arrayref;

@@ -737,7 +664,7 @@ helper 'check_if_user_name_exists' => sub {
helper 'get_user_travels' => sub {
	my ( $self, $limit ) = @_;

	my $uid   = $self->get_user_id;
	my $uid   = $self->current_user->{id};
	my $query = $self->app->get_all_actions_query;
	if ($limit) {
		$query = $self->app->get_last_actions_query;
@@ -800,7 +727,7 @@ helper 'get_user_travels' => sub {
helper 'get_user_status' => sub {
	my ($self) = @_;

	my $uid = $self->get_user_id;
	my $uid = $self->current_user->{id};
	$self->app->get_last_actions_query->execute($uid);
	my $rows = $self->app->get_last_actions_query->fetchall_arrayref;

@@ -886,176 +813,33 @@ helper 'navbar_class' => sub {

get '/' => sub {
	my ($self) = @_;
	if ( $self->is_user_authenticated ) {
		$self->render( 'landingpage', with_geolocation => 1 );
};

post '/action' => sub {
	my ($self) = @_;
	my $params = $self->req->json;

	if ( not exists $params->{action} ) {
		$params = $self->req->params->to_hash;
	}

	if ( not $params->{action} ) {
		$self->render(
			json => {
				success => 0,
				error   => 'Missing action value',
			},
			status => 400,
		);
		return;
	}

	my $station = $params->{station};

	if ( $params->{action} eq 'checkin' ) {

		my ( $train, $error )
		  = $self->checkin( $params->{station}, $params->{train}, );

		if ($error) {
			$self->render(
				json => {
					success => 0,
					error   => $error,
				},
			);
		}
		else {
			$self->render(
				json => {
					success => 1,
				},
			);
		}
	}
	elsif ( $params->{action} eq 'checkout' ) {
		my $error = $self->checkout( $params->{station}, $params->{force}, );

		if ($error) {
			$self->render(
				json => {
					success => 0,
					error   => $error,
				},
			);
	}
	else {
			$self->render(
				json => {
					success => 1,
				},
			);
		}
		$self->render( 'landingpage', intro => 1 );
	}
	elsif ( $params->{action} eq 'undo' ) {
		my $error = $self->undo;
		if ($error) {
			$self->render(
				json => {
					success => 0,
					error   => $error,
				},
			);
		}
		else {
			$self->render(
				json => {
					success => 1,
				},
			);
		}
	}
	else {
		$self->render(
			json => {
				success => 0,
				error   => 'invalid action value',
			},
			status => 400,
		);
	}
};

get '/a/account' => sub {
	my ($self) = @_;

	$self->render('account');
};

get '/a/export.json' => sub {
	my ($self) = @_;
	my $uid    = $self->get_user_id;
	my $query  = $self->app->get_all_actions_query;

	$query->execute($uid);

	my @entries;

	while ( my @row = $query->fetchrow_array ) {
		my (
			$action,       $raw_ts,      $ds100,     $name,
			$train_type,   $train_line,  $train_no,  $train_id,
			$raw_sched_ts, $raw_real_ts, $raw_route, $raw_messages
		) = @row;

		$name         = decode( 'UTF-8', $name );
		$raw_route    = decode( 'UTF-8', $raw_route );
		$raw_messages = decode( 'UTF-8', $raw_messages );
		push(
			@entries,
			{
				action        => $action_types[ $action - 1 ],
				action_ts     => $raw_ts,
				station_ds100 => $ds100,
				station_name  => $name,
				train_type    => $train_type,
				train_line    => $train_line,
				train_no      => $train_no,
				train_id      => $train_id,
				scheduled_ts  => $raw_sched_ts,
				realtime_ts   => $raw_real_ts,
				messages      => $raw_messages
				? [ map { [ split(qr{:}) ] } split( qr{[|]}, $raw_messages ) ]
				: undef,
				route => $raw_route ? [ split( qr{[|]}, $raw_route ) ]
				: undef,
			}
		);
	}

	$self->render(
		json => [@entries],
	);
};

get '/a/history' => sub {
	my ($self) = @_;

	$self->render('history');
};

get '/x/about' => sub {
get '/about' => sub {
	my ($self) = @_;

	$self->render( 'about', version => $VERSION );
};

get '/x/impressum' => sub {
get '/impressum' => sub {
	my ($self) = @_;

	$self->render('imprint');
};

get '/x/imprint' => sub {
get '/imprint' => sub {
	my ($self) = @_;

	$self->render('imprint');
};

post '/x/geolocation' => sub {
post '/geolocation' => sub {
	my ($self) = @_;

	my $lon = $self->param('lon');
@@ -1085,12 +869,12 @@ post '/x/geolocation' => sub {

};

get '/x/login' => sub {
get '/login' => sub {
	my ($self) = @_;
	$self->render('login');
};

post '/x/login' => sub {
post '/login' => sub {
	my ($self)   = @_;
	my $user     = $self->req->param('user');
	my $password = $self->req->param('password');
@@ -1114,18 +898,12 @@ post '/x/login' => sub {
	}
};

get '/x/logout' => sub {
	my ($self) = @_;
	$self->logout;
	$self->redirect_to('/x/login');
};

get '/x/register' => sub {
get '/register' => sub {
	my ($self) = @_;
	$self->render('register');
};

post '/x/register' => sub {
post '/register' => sub {
	my ($self)    = @_;
	my $user      = $self->req->param('user');
	my $email     = $self->req->param('email');
@@ -1163,8 +941,7 @@ post '/x/register' => sub {
		return;
	}

	#if ( $self->check_if_user_name_exists($user) or $user eq 'dev' ) {
	if ( $user ne $self->get_user_name ) {
	if ( $self->check_if_user_name_exists($user) ) {
		$self->render( 'register', invalid => 'user_collision' );
		return;
	}
@@ -1181,14 +958,14 @@ post '/x/register' => sub {

	my $token   = make_token();
	my $pw_hash = hash_password($password);
	my $user_id = $self->get_user_id( $user, $email, $token, $pw_hash );
	my $user_id = $self->add_user( $user, $email, $token, $pw_hash );

	my $body = "Hallo, ${user}!\n\n";
	$body .= "Mit deiner E-Mail-Adresse (${email}) wurde ein Account auf\n";
	$body .= "travelynx.finalrewind.org angelegt.\n\n";
	$body
	  .= "Falls die Registrierung von dir ausging, kannst du den Account unter\n";
	$body .= "https://travelynx.finalrewind.org/x/reg/${user_id}/${token}\n";
	$body .= "https://travelynx.finalrewind.org/reg/${user_id}/${token}\n";
	$body .= "freischalten.\n\n";
	$body
	  .= "Falls nicht, ignoriere diese Mail bitte. Nach 48 Stunden wird deine\n";
@@ -1200,7 +977,7 @@ post '/x/register' => sub {
	$body .= " * Datum: ${date}\n";
	$body .= " * Verwendete IP: ${ip}\n";
	$body .= " * Verwendeter Browser gemäß User Agent: ${ua}\n\n\n";
	$body .= "Impressum: https://travelynx.finalrewind.org/x/impressum\n";
	$body .= "Impressum: https://travelynx.finalrewind.org/impressum\n";

	my $reg_mail = Email::Simple->create(
		header => [
@@ -1221,7 +998,7 @@ post '/x/register' => sub {
	}
};

get '/x/reg/:id/:token' => sub {
get '/reg/:id/:token' => sub {
	my ($self) = @_;

	my $id    = $self->stash('id');
@@ -1244,7 +1021,166 @@ get '/x/reg/:id/:token' => sub {
	$self->render( 'login', from => 'verification' );
};

get '/*station' => sub {
under sub {
	my ($self) = @_;
	return $self->is_user_authenticated;
};

post '/action' => sub {
	my ($self) = @_;
	my $params = $self->req->json;

	if ( not exists $params->{action} ) {
		$params = $self->req->params->to_hash;
	}

	if ( not $params->{action} ) {
		$self->render(
			json => {
				success => 0,
				error   => 'Missing action value',
			},
			status => 400,
		);
		return;
	}

	my $station = $params->{station};

	if ( $params->{action} eq 'checkin' ) {

		my ( $train, $error )
		  = $self->checkin( $params->{station}, $params->{train}, );

		if ($error) {
			$self->render(
				json => {
					success => 0,
					error   => $error,
				},
			);
		}
		else {
			$self->render(
				json => {
					success => 1,
				},
			);
		}
	}
	elsif ( $params->{action} eq 'checkout' ) {
		my $error = $self->checkout( $params->{station}, $params->{force}, );

		if ($error) {
			$self->render(
				json => {
					success => 0,
					error   => $error,
				},
			);
		}
		else {
			$self->render(
				json => {
					success => 1,
				},
			);
		}
	}
	elsif ( $params->{action} eq 'undo' ) {
		my $error = $self->undo;
		if ($error) {
			$self->render(
				json => {
					success => 0,
					error   => $error,
				},
			);
		}
		else {
			$self->render(
				json => {
					success => 1,
				},
			);
		}
	}
	else {
		$self->render(
			json => {
				success => 0,
				error   => 'invalid action value',
			},
			status => 400,
		);
	}
};

get '/account' => sub {
	my ($self) = @_;

	$self->render('account');
};

get '/history' => sub {
	my ($self) = @_;

	$self->render('history');
};

get '/export.json' => sub {
	my ($self) = @_;
	my $uid    = $self->current_user->{id};
	my $query  = $self->app->get_all_actions_query;

	$query->execute($uid);

	my @entries;

	while ( my @row = $query->fetchrow_array ) {
		my (
			$action,       $raw_ts,      $ds100,     $name,
			$train_type,   $train_line,  $train_no,  $train_id,
			$raw_sched_ts, $raw_real_ts, $raw_route, $raw_messages
		) = @row;

		$name         = decode( 'UTF-8', $name );
		$raw_route    = decode( 'UTF-8', $raw_route );
		$raw_messages = decode( 'UTF-8', $raw_messages );
		push(
			@entries,
			{
				action        => $action_types[ $action - 1 ],
				action_ts     => $raw_ts,
				station_ds100 => $ds100,
				station_name  => $name,
				train_type    => $train_type,
				train_line    => $train_line,
				train_no      => $train_no,
				train_id      => $train_id,
				scheduled_ts  => $raw_sched_ts,
				realtime_ts   => $raw_real_ts,
				messages      => $raw_messages
				? [ map { [ split(qr{:}) ] } split( qr{[|]}, $raw_messages ) ]
				: undef,
				route => $raw_route ? [ split( qr{[|]}, $raw_route ) ]
				: undef,
			}
		);
	}

	$self->render(
		json => [@entries],
	);
};

post '/logout' => sub {
	my ($self) = @_;
	$self->logout;
	$self->redirect_to('/login');
};

get '/s/*station' => sub {
	my ($self) = @_;
	my $station = $self->stash('station');

+2 −2
Original line number Diff line number Diff line
@@ -25,14 +25,14 @@ $(document).ready(function() {
				stationlink.attr('href', ds100);
				stationlink.text(name);

				resultBody.append('<tr><td><a href="/' + ds100 + '">' + name + '</a></td></tr>');
				resultBody.append('<tr><td><a href="/s/' + ds100 + '">' + name + '</a></td></tr>');
			});
			placeholder.replaceWith(resultTable);
		}
	};

	var processLocation = function(loc) {
		$.post('/x/geolocation', {lon: loc.coords.longitude, lat: loc.coords.latitude}, processResult);
		$.post('/geolocation', {lon: loc.coords.longitude, lat: loc.coords.latitude}, processResult);
	};

	var processError = function(error) {
+1 −1
Original line number Diff line number Diff line
$(document).ready(function(){var e=$("p.geolocationhint"),t=$("div.geolocation div.progress"),o=function(o,a,n){e.remove(),t.remove()},a=function(e){e.error?o(0,e.error):0==e.candidates.length?o():(resultTable=$("<table><tbody></tbody></table>"),resultBody=resultTable.children(),$.each(e.candidates,function(e,t){var o=t.ds100,a=t.name,n=t.distance;n=n.toFixed(1);var r=$(document.createElement("a"));r.attr("href",o),r.text(a),resultBody.append('<tr><td><a href="/'+o+'">'+a+"</a></td></tr>")}),t.replaceWith(resultTable))},n=function(e){$.post("/x/geolocation",{lon:e.coords.longitude,lat:e.coords.latitude},a)},r=function(e){e.code==e.PERMISSION_DENIED?o():e.code==e.POSITION_UNAVAILABLE?o():(e.code,e.TIMEOUT,o())};navigator.geolocation?navigator.geolocation.getCurrentPosition(n,r):o()});
$(document).ready(function(){var a=$("p.geolocationhint"),n=$("div.geolocation div.progress"),t=function(e,t,o){a.remove(),n.remove()},o=function(e){e.error?t(0,e.error):0==e.candidates.length?t():(resultTable=$("<table><tbody></tbody></table>"),resultBody=resultTable.children(),$.each(e.candidates,function(e,t){var o=t.ds100,a=t.name,n=t.distance;n=n.toFixed(1);var r=$(document.createElement("a"));r.attr("href",o),r.text(a),resultBody.append('<tr><td><a href="/s/'+o+'">'+a+"</a></td></tr>")}),n.replaceWith(resultTable))};navigator.geolocation?navigator.geolocation.getCurrentPosition(function(e){$.post("/geolocation",{lon:e.coords.longitude,lat:e.coords.latitude},o)},function(e){e.code==e.PERMISSION_DENIED||e.code==e.POSITION_UNAVAILABLE||(e.code,e.TIMEOUT),t()}):t()});
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ $(document).ready(function() {
			station: link.data('station'),
			force: link.data('force'),
		};
		tvly_run(link, req, '/' + req.station, function() {
		tvly_run(link, req, '/s/' + req.station, function() {
			link.append(' – Ohne Echtzeitdaten auschecken?')
			link.data('force', true);
		});
+1 −1
Original line number Diff line number Diff line
function tvly_run(n,t,i,a){var c='<i class="material-icons">error</i>',o=$('<div class="progress"><div class="indeterminate"></div></div>');n.hide(),n.after(o),$.post("/action",t,function(t){t.success?$(location).attr("href",i):(M.toast({html:c+" "+t.error}),o.remove(),a&&a(),n.append(" "+c),n.show())})}$(document).ready(function(){$(".action-checkin").click(function(){var t=$(this);tvly_run(t,{action:"checkin",station:t.data("station"),train:t.data("train")},"/")}),$(".action-checkout").click(function(){var t=$(this),n={action:"checkout",station:t.data("station"),force:t.data("force")};tvly_run(t,n,"/"+n.station,function(){t.append(" – Ohne Echtzeitdaten auschecken?"),t.data("force",!0)})}),$(".action-undo").click(function(){tvly_run($(this),{action:"undo"},window.location.href)})});
function tvly_run(n,t,i,a){var c='<i class="material-icons">error</i>',o=$('<div class="progress"><div class="indeterminate"></div></div>');n.hide(),n.after(o),$.post("/action",t,function(t){t.success?$(location).attr("href",i):(M.toast({html:c+" "+t.error}),o.remove(),a&&a(),n.append(" "+c),n.show())})}$(document).ready(function(){$(".action-checkin").click(function(){var t=$(this);tvly_run(t,{action:"checkin",station:t.data("station"),train:t.data("train")},"/")}),$(".action-checkout").click(function(){var t=$(this),n={action:"checkout",station:t.data("station"),force:t.data("force")};tvly_run(t,n,"/s/"+n.station,function(){t.append(" – Ohne Echtzeitdaten auschecken?"),t.data("force",!0)})}),$(".action-undo").click(function(){tvly_run($(this),{action:"undo"},window.location.href)})});
Loading